Komunikacja z serwerem uslugi DNS.
Transkrypt
Komunikacja z serwerem uslugi DNS.
Protokół DNS Domain Name System Aplikacja dnsquery dr Zbigniew Lipiński Instytut Matematyki i Informatyki ul. Oleska 48 50-204 Opole [email protected] Protokół DNS DNS, (ang.) Domain Name System. Specyfikacje protokołu i usługi DNS: RFC 1034, P.V. Mockapetris, Domain names - concepts and facilities. RFC 1035, P.V. Mockapetris, Domain names - implementation and specification. RFC 1995, M. Ohta, Incremental Zone Transfer in DNS. RFC 2136, P. Vixie, Ed., S. Thomson, Y. Rekhter, Dynamic Updates in the Domain Name System (DNS UPDATE). RFC 2181, R. Elz, R. Bush, Clarifications to the DNS Specification. RFC 2308. M. Andrews, Negative Caching of DNS Queries (DNS NCACHE). RFC 2537, D. Eastlake, RSA/MD5 KEYs and SIGs in the Domain Name System (DNS). RFC 3596, S. Thomson, C. Huitema, V. Ksinant, M. Souissi, DNS Extensions to Support IP Version 6. W warstwie transportowej modelu referencyjnego dla OSI protokół DNS wykorzystuje: • protokół UDP, port serwera DNS 53, • protokół TCP, port serwera DNS 53. Wiadomości przesyłane w protokole UDP mogą mieć maks. wielkość 512 bajtów (bez nagłówka IP, UDP). Protokół UDP stosowany jest do standardowych zapytań do serwera nazw. Do transferu informacji o strafach serwery nazw powinny stosować protokół TCP. 2 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Protokół i usługa DNS Protokół DNS wykorzystywany jest przez usługę DNS, (ang.) Domain Name System Service. Domain Name System jest hierarchiczna, rozproszoną bazą danych. System DNS definiuje: • schemat baz DNS, • mechanizm zapytań i uaktualniania danych w bazach DNS, • mechanizm replikacji danych między bazami. Usługa DNS pozwala użytkownikom sieci na posługiwanie się do lokalizacji sieci, hostów, usług nazw dns’owych ('naturalnych’ nazw i adresów) zamiast adresów IP. Usługa DNS służy do tłumaczenia nazw sieci (nazw domen), dns’owych nazw hostów, dns’owych adresów serwerów usług, URL na ich adresy IP. Usługa DNS została zaimplementowana po raz pierwszy: • w 1984 w systemie Windows NT Server 4, • w systemie UNIX BSD 4.3, jako BIND, (ang.) Berkeley Internet Name Domain (1986). 3 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Komponenty systemu DNS Komponenty systemu DNS: • DOMAIN NAME SPACE - struktura (hierarchia) drzewa nazw w domenach. • RESOURCE RECORDS - struktura danych w bazach DNS. • NAME SERVERS - serwery nazw, oprogramowanie służące do wykonywania operacji na bazach DNS. • RESOLVERS - programy które pośredniczą w komunikacji między programem użytkownika a serwerami nazw. Resolvery znajdują się po stronie klienta i serwera. Zewnetrzny serwer nazw Baza DNS Program Uzytkownika Pytanie Pytanie Resolver Serwer nazw Odpowiedz Odpowiedz Pytanie Odpowiedz cache Baza DNS Konfiguracja uslugi DNS 4 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Protokół i usługa DNS Usługa DNS wprowadza hierarchie nazw dla sieci, podsieci w Internecie. Hosty, podsieci, sieci grupowane są w domeny dn’sowe. Domena - jest zbiorem hostów, zbiorem sieci charakteryzujących się wspólnymi zasadami zarządzania, bezpieczeństwa, wspólną nazwą. Domeny, i ich nazwy, posiadają hierarchiczną strukturę. Na szczycie hierarchii znajduje się domena główna (root domain). Informacja o domenach jest zawarta w rozproszonej bazie, znajdujących się na serwerach nazw (name servers). Strefa - (ang.) zone, podzbiór obszaru nazw DNS zarządzany przez jeden serwer nazw. Nazwa domeny - to ciąg nazw poszczególnych obszarów w hierarchii domeny oddzielonych kropkami. Przykład: Nazwa domeny. math.uni.opole.pl Przykład: Nazwa hosta w domenie math.uni.opole.pl o netbiosowej nazwie host1. host1.math.uni.opole.pl 5 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Narzędzie nslookup RFC 2151, G. Kessler, S. Sheppard,'A Primer On Internet and TCP/IP Tools and Utilities', 1997. Nslookup narzędzie umożliwiające wyszukiwanie danych na serwerach DNS, służące również do testowania połączeń z serwerem DNS. Składnia: nslookup [-opcja] [nazwa_hosta] [serwer] Wybrae opcje: all - drukuje opcje, informacje o bieżącym serwerze i hoście [no]defname - dołącza nazwę domeny do każdej kwerendy [no]recurse - prosi o rekurencyjną odpowiedź na kwerendę [no]search - używa listy przeszukiwania domen domain=NAZWA - ustawia domyślną nazwę domeny na NAZWA srchlist=N1[/N2/.../N6] - ustawia domenę na N1, a listę przeszukiwania na N1, N2, itd. root=NAZWA - ustawia serwer główny na NAZWA retry=X - ustawia liczbę ponawianych prób na X timeout=X - ustawia początkowy limit czasu na X sekund type=X - ustawia typ kwerendy (np. A, ANY, CNAME, MX, NS, PTR, SOA, SRV) class=X - ustawia klasę zapytania (np. IN (Internet), ANY) [no]msxfr - używa szybkiego transferu strefy MS ixfrver=X - bieżąca wersja używana w żądaniu transferu IXFR 6 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja struktury GUID Nazwa struktury : GUID Opis Atrybuty : Struktura GUID opisuje identyfikator obiektu ‘globally unique identifier’. : Data1 Data2 Data3 Data4 – wartość unsigned long integer. wartość unsigned short integer. wartość unsigned short integer. tablica unsigned characters. Implementacja struktury GUID: typedef struct _GUID { unsigned unsigned unsigned unsigned } GUID; long short short char Data1; Data2; Data3; Data4[8]; 7 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja struktury AFPROTOCOLS Nazwa struktury : AFPROTOCOLS Opis Atrybuty : Struktura AFPROTOCOLS dostarcza listę protokołów do jakich programiści mogą ograniczyć zapytania. : iAddressFamily – iProtocol – Rodzina adresów do jakich zapytanie ma być ograniczone. Protokół do jakiego zapytanie ma być ograniczone. Implementacja struktury AFPROTOCOLS: typedef struct _AFPROTOCOLS { INT iAddressFamily; INT iProtocol; } AFPROTOCOLS, *PAFPROTOCOLS, *LPAFPROTOCOLS; 8 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja struktury AFPROTOCOLS Tablica afproto[2] Tablica afproto[2]. AFPROTOCOLS afproto[2] = { {AF_INET, IPPROTO_UDP}, {AF_INET, IPPROTO_TCP} }; AF_INET- oznacza rodzinę adresów TCP/IPv4, (inne wartości: AF_INET6, AF_UNSPEC). Opcja gniazda: IPPROTO_UDP Wartość: UDP_NOCHECKSUM Typ: BOOL Jeżeli ta opcja jest ustawiona, datagramy UDP są wysyłane z zerową sumą kontrolną. Obsługa tej opcji jest wymagana. Jeżeli ‘service provider’ nie posiada mechanizmu blokowania liczenia sumy kontrolnej, może ignorować tą opcję. Opcja gniazda: IPPROTO_TCP Wartość: TCP_EXPEDITED_1122 RFC 11 22, R. Braden, Requirements for Internet Hosts - Communication Layers, 1989. Typ: BOOL Jeżeli opcja jest ustawiona, ‘service provider’ implementuje format wysyłanych danych zgodnie ze specyfikacją RFC-1222. W pozostałych przypadkach, jako format domyślny, używany jest format ‘Berkeley Software Distribution (BSD)’. Opcja jest ustawiana dla połączenia tylko raz, tzn. nie może być zmieniana lub wyłączona w trakcie połączenia. Opcja nie jest wymagana. 9 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja struktury WSAQUERYSET Nazwa struktury : WSAQUERYSET Opis: Struktura WSAQUERYSET dostarcza informacji o danej usłudze: ID klasy usługi (service class ID), nazwę usługi, identyfikator obszaru nazw (name-space identifier), adresy IP z portami na których nasłuchuje serwer usługi. Atrybuty : dwSize – Musi być wartość sizeof(WSAQuerySet). Parametr służy do określenia wersji. lpszServiceInstanceName - Parametr opcjonalny. Wskaźnik do nazwy usługi. lpServiceClassId Parametr wymagany. GUID dla danej klasy usługi. lpVersion Parametr opcjonalny. Wskaźnik do zmiennej zawierającej wymaganą wersję. lpszComment Parametr ignorowanych przy zapytaniach. dwNameSpace Identyfikator obszaru nazw do którego ma być ograniczone przeszukiwane informacji o usłudze (parametr NS_ALL oznacza przeszukiwanie wszystkich obszarów nazw). lpNSProviderId Parametr opcjonalny. Wskaźnik do GUID w określonym obszarze nazw ‘service provider’, zapytania są ograniczane tylko do tego ‘sp’. lpszContext Parametr opcjonalny. Wskaźnik określa początkowy obszar nazw do którego będzie wysłane zapytanie. dwNumberOfProtocols – Wielkość tablicy zawierającej listę protokołów do których ograniczone są zapytania (w bajtach). Wartość może być zero. lpafpProtocols Parametr opcjonalny. Wskazuje na tablice struktur AFPROTOCOLS. Only services that utilize these protocols will be returned. lpszQueryString Parametr opcjonalny. Pewne obszary nazw (jak Whois++) posiadają mechanizm obsługi ‘enriched SQL-like queries’ które zawierają zapytania w formacie string txt. Parametr służy do określania tego stringu. dwNumberOfCsAddrs - Parametr ignorowanych przy zapytaniach. lpcsaBuffer Parametr ignorowanych przy zapytaniach. dwOutputFlags Parametr ignorowanych przy zapytaniach. lpBlob Parametr opcjonalny. Wskaźnik do określonego ‘providera’ (pointer to a providerspecific entity). 10 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Implementacja struktury WSAQUERYSET typedef struct _WSAQuerySet { DWORD dwSize; LPTSTR lpszServiceInstanceName; LPGUID lpServiceClassId; LPWSAVERSION lpVersion; LPTSTR lpszComment; DWORD dwNameSpace; LPGUID lpNSProviderId; LPTSTR lpszContext; DWORD dwNumberOfProtocols; LPAFPROTOCOLS lpafpProtocols; LPTSTR lpszQueryString; DWORD dwNumberOfCsAddrs; LPCSADDR_INFO pcsaBuffer; DWORD dwOutputFlags; LPBLOB pBlob; } WSAQUERYSET, *PWSAQUERYSETW; 11 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja struktury BLOB Nazwa struktury : BLOB Opis : Atrybuty : Struktura BLOB, (wyznaczana z Binary Large Object) zawiera informację o bloku danych. cbSize pBlobData - Wielkość bloku danych (w bajtach) wskazywany przez pBlobData. - Wskaźnik do bloku danych. Implementacja struktury BLOB: typedef struct _BLOB { ULONG BYTE* } BLOB; cbSize; pBlobData; 12 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja struktury hostent Nazwa struktury : hostent Opis : Struktura jest używana przez funkcje do przechowywania informacji o hoście. Zadeklarowana w pliku Winsock2.h Atrybuty : h_name – Nazwa hosta. Jeżeli jest używany system DNS (lub podobny) zmienna zawiera pełną nazwę DNS’ową hosta FQDN (ang. Fully Qualified Domain Name). W pliku hosts, wartość zmiennej jest drugim wpisem po adresie IP. h_aliases - Zerem zakończona tablica alternatywnych nazw hosta. h_addrtype - Typ adresu. h_length - Długość w bajtach każdego adresu. h_addr_list - Zerem zakończona lista adresów IP hosta. Adresy IP są zwracane w sieciowym uporządkowaniu bajtów (Big Endian). Makro h_addr zastępuje h_addr_list[0] w celu zgodności ze starszymi wersjami oprogramowania. Przykład: char *ServerName; LPHOSTENT hp; SOCKADDR_IN AdresSerwera; hp = gethostbyname(ServerName); AdresSerwera.sin_addr.s_addr = hp->h_addr; Implementacja struktury hostent: typedef struct hostent { char FAR* char FAR FAR** short short char FAR FAR** } hostent; h_name; h_aliases; h_addrtype; h_length; h_addr_list; 13 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 karty. Jeśli w polu jest wartość INADDR_ANY, to nasłuchiwanmnie będzie prowadzone na wszystkich adresach, jakie posiada dany host. 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 unsigned short struct in_addr char }; Przykład: sin_family; sin_port; sin_addr; sin_zero[8]; char *ServerName; LPHOSTENT hp; SOCKADDR_IN AdresSerwera; hp = gethostbyname(ServerName); AdresSerwera.sin_addr.s_addr = hp->h_addr; 14 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja struktury in_addr Nazwa struktury : in_addr Opis: Struktura in_addr adres IP hosta. Struktura zdefiniowana w WINSOCK.H Atrybuty : S_un_b S_un_w S_addr - adres hosta w formacie u_chars. adres hosta w formacie dwóch u_shorts. adres hosta w formacie u_long. Implementacja struktury in_addr: 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; }; 15 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja funkcji FixList() Nazwa funkcji : FixList() Zwracana wartość: void Argumenty : PCHAR ** , PCHAR Opis : Funkcja FixList() pobiera tablicę znaków zwróconą przez funkcję WSALookupServiceNext() modyfikuje je poprzez dodanie znaku. Implementacja funkcji FixList(): void FixList(PCHAR ** List, PCHAR Base) { if (*List) { PCHAR * Addr; Addr = *List = (PCHAR *)( ((DWORD)*List + Base) ); while(*Addr) { *Addr = (PCHAR)(((DWORD)*Addr + Base)); Addr++; } } } 16 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja funkcji UnpackHostEnt() Nazwa funkcji : UnpackHostEnt() Zwracana wartość: void Argumenty Opis : struct hostent * : Funkcja UnpackHostEnt() dokleja do atrybutu h_name struktury hostent znak pch = (PCHAR)hostent, jeżeli wartość atrybutu h_name jest zero wywołuje funkcję FixList() (funkcja dołącza do atrybutu h_aliases, h_addr_list struktury hostent znak pch = (PCHAR)hostent. Implementacja funkcji UnpackHostEnt(): void UnpackHostEnt(struct hostent * hostent) { PCHAR pch; pch = (PCHAR)hostent; if(hostent->h_name) { hostent->h_name = (PCHAR)((DWORD)hostent->h_name + pch); } FixList(&hostent->h_aliases, pch); FixList(&hostent->h_addr_list, pch); } 17 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja funkcji WSALookupServiceBegin() Nazwa funkcji : WSALookupServiceBegin() Zwracana wartość: INT Argumenty : lpqsRestrictions - [in] Wskaźnik od zmiennej zwierającej parametry wyszukiwania. dwControlFlags - [in] Flaga służąca do kontroli ‘głębokości’ wyszukiwania: LUP_DEEP, LUP_CONTAINERS, LUP_NOCONTAINERS, LUP_FLUSHCACHE, LUP_FLUSHPREVIOUS, LUP_NEAREST, LUP_RES_SERVICE, LUP_RETURN_ALIASES,LUP_RETURN_NAME, LUP_RETURN_TYPE, LUP_RETURN_VERSION, LUP_RETURN_COMMENT, LUP_RETURN_ADDR, LUP_RETURN_BLOB, LUP_RETURN_ALL lphLookup - [out] Uchwyt do wywoływanej funkcji WSALookupServiceNext() w celu rozpoczęcia uzyskiwania parametrów. Opis : Funkcja WSALookupServiceBegin() służy do inicjowania zapytań klienta o informacje dotyczące graniczeń zapytań zawartych w strukturze WSAQUERYSET. Funkcja WSALookupServiceBegin() tylko zwraca uchwyt który powinien być użyty przez kolejne zapytania funkcją WSALookupServiceNext(). Nagłówek zadeklarowany w pliku Winsock2.h. Implementacja w pliku Use Ws2_32.lib. 18 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja funkcji WSALookupServiceNext() Nazwa funkcji : WSALookupServiceNext() Zwracana wartość: INT Funkcja zawraca zero gdy operacja zakończyła się sukcesem, jeśli nie to funkcja zwraca wartość SOCKET_ERROR Argumenty : hLookup - [in] Uchwyt zwrócony przez funkcje WSALookupServiceBegin(). dwControlFlags - [in] Flaga służąca do kontroli zapytania. Currently only LUP_FLUSHPREVIOUS is defined as a means to cope with a result set which is too large. If an application does not (or cannot) supply a large enough buffer, setting LUP_FLUSHPREVIOUS instructs the provider to discard the last result set—which was too large—and move on to the next set for this call. lpdwBufferLength - [in, out] Na wejściu, wskaźnik do zmiennej zawierającej liczbę bajtów w buforze (wskazywanym przez lpqsResults. Na wyjściu, gdy funkcja nie zwróci kodu błędu WSAEFAULT, wskaźnik wskazuje na minimalną liczbę bajtów jaką powinien zawierać bufor aby odebrać dane. lpqsResults - [out] Wskaźnik do pamięci który zawiera strukturę WSAQUERYSET Opis : Funkcja WSALookupServiceNext() jest wywoływana po uzyskaniu uchwytu od funkcji WSALookupServiceBegin() w celu uzyskania informacji o usłudze. ‘Service provider’ zwraca dane w strukturze WSAQUERYSET do bufora wskazywanego przez lpqsResults. Klient wywołuje tą funkcję tak długo aż funkcja nie zwróci WSA_E_NO_MORE (co oznacza, że wszystkie dane WSAQUERYSET zostały zwrócone). 19 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja funkcji WSALookupServiceEnd() Nazwa funkcji : WSALookupServiceEnd() Zwracana wartość: INT Funkcja zawraca zero gdy operacja zakończyła się sukcesem, jeśli nie to funkcja zwraca wartość SOCKET_ERROR Argumenty : hLookup - [in] Uchwyt uzyskany przez wywołanie funkcji WSALookupServiceBegin(). Opis : Funkcja WSALookupServiceEnd() służy od zwalniania uchwytu utworzonego przez funkcję WSALookupServiceBegin(). Wywołanie funkcji WSALookupServiceEnd() z innego wątku, gdy wątek funkcji WSALookupServiceNext() jest zablokowany, kasuje zapytanie i powoduje, że funkcja WSALookupServiceNext() natychmiast zwraca zapytanie. 20 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja projektu Nazwa projektu: dnsquery Typ projektu: Win32 console application Lista plików: dnsquery.cpp Metoda kompilacji: 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ę: dnsquery -> przycisk (OK) -> Okno Win32 application wizard – dnsquery-> wybrać: Application settings -> wybrać: Empty project-> Przycisk (Finish). Konfiguracja projektu: (-)Project-> nazwa_projektu Properies... -> Configuration Properies-> Linker-> Input -> Additional Dependecies, wpisać: WS2_32.Lib. W pliku dnsquery.vcproj, atrybutowi CharacterSet tagu Configuration przypisać wartość 2, tzn. <Configuration CharacterSet="2”> Funkcjonalność: (Run-> cmd) wpisać: \> dnsquery nazwa_hosta 21 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Specyfikacja projektu Pliki nagłówkowe: winsock2.h, SvcGuid.h (VCID_INET_HOSTADDRBYNAME), iostream Funkcje programu: WSAStartup(), WSAGetLastError(), WSALookupServiceBegin(), WSALookupServiceNext(), WSALookupServiceEnd(), WSACleanup(), FixList(), UnpackHostEnt() Struktury programu: WSADATA, GUID, AFPROTOCOLS, WSAQUERYSET, BLOB, HOSTENT, SOCKADDR_IN Zmienne programu: WSADATA WSAQUERYSET char wsd; *qs=NULL; buff[RNR_BUFFER_SIZE]; // specjalna wartość struktury GUID: SVCID_INET_HOSTADDRBYNAME dla rozwiązania nazwy hosta GUID HostnameGuid = SVCID_INET_HOSTADDRBYNAME; HANDLE AFPROTOCOLS DWORD int LPBLOB HOSTENT SOCKADDR_IN hRnr; afproto[2] = { {AF_INET, IPPROTO_UDP}, {AF_INET, IPPROTO_TCP} }; dwLength = RNR_BUFFER_SIZE; ret; pvRet = NULL; *hp = NULL; addr; 22 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Struktura programu (struktura funkcji main()) 1.Sprawdzenie listy argumentów. 2. Sprawdzenie wersji Winsock. WSAStartup(MAKEWORD(2,2), &wsd) != 0 ? 3. Inicjowanie struktury WSAQUERYSET. qs = (WSAQUERYSET *)buff; // qs wskaźnik do struktury WSAQUERYSET qs->dwSize = sizeof(WSAQUERYSET); qs->lpszServiceInstanceName = argv[1]; qs->lpServiceClassId = &HostnameGuid; qs->dwNameSpace = NS_ALL; qs->dwNumberOfProtocols = 2; // TCP i UDP qs->lpafpProtocols = afproto; 4. Początek sesji zapytań klienta do serwera DNS. Dane do inicjowania sesji pochodzą ze struktury WSAQUERYSET. Utworzenie uchwytu do sesji, który następnie będzie wykorzystywany do zapytań przez funkcję WSALookupServiceNext(). ret = WSALookupServiceBegin(qs, LUP_RETURN_BLOB | LUP_RETURN_NAME, &hRnr); 23 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Struktura funkcji main() 5. Sprawdzenie czy funkcja WSALookupServiceBegin() nie zwróciła błędu. Czy ret == NO_ERROR ? 6. Wywołanie funkcji WSALookupServiceNext(), sprawdzenie czy funkcja nie zwróciła błędu. ret = WSALookupServiceNext(hRnr, 0, &dwLength, qs); Czy ret != NO_ERROR ? 7. Jeżeli funkcja WSALookupServiceNext() zwróciła błąd sprawdzenie numeru błędu i zakończenie sesji Czy WSAGetLastError() == WSASERVICE_NOT_FOUND ? WSALookupServiceEnd(hRnr); 8. Sprawdzenie czy serwer DNS zwrócił dane do struktury BLOB. Czy qs->lpBlob == NULL ? 9. Utworzenie bufora na dane. hp = new HOSTENT [qs->lpBlob->cbSize]; lub hp = (HOSTENT *)LocalAlloc(LPTR, qs->lpBlob->cbSize); 10. Rozwinięcie listy hostów. UnpackHostEnt(hp); 24 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego Struktura funkcji main() 11. Przekierowanie adresów na ekran. for(register int i=0; hp->h_addr_list[i] ;i++) { memcpy(&addr.sin_addr, hp->h_addr_list[i], hp->h_length); cout << argv[1] << " IP: " << inet_ntoa(addr.sin_addr) << endl; } for(i=0; hp->h_aliases[i] ;i++) cout << "Alias: " << hp->h_aliases[i] << endl; 12. Zwolnienie pamięci i zamknięcie sesji. delete [] hp; // lub LocalFree(hp); WSACleanup(); 25 Z. Lipiński, Instytut Matematyki i Informatyki, Uniwersytet Opolski, Podstawy programowania sieciowego // dnsquery.cpp #include <winsock2.h> #include <SvcGuid.h> // VCID_INET_HOSTADDRBYNAME #include <iostream> using namespace std; #define RNR_BUFFER_SIZE (sizeof(WSAQUERYSET) + sizeof(struct hostent) + 1024) void FixList(PCHAR ** List, PCHAR Base) { if (*List) { PCHAR * Addr; Addr = *List = (PCHAR *)( ((DWORD)*List + Base) ); while(*Addr) { *Addr = (PCHAR)(((DWORD)*Addr + Base)); Addr++; } } } //koniec FixList() void UnpackHostEnt(struct hostent * hostent) { PCHAR pch; pch = (PCHAR)hostent; if(hostent->h_name) { hostent->h_name = (PCHAR)((DWORD)hostent->h_name + pch); } FixList(&hostent->h_aliases, pch); FixList(&hostent->h_addr_list, pch); } //koniec UnpackHostEnt() 26 int main(int argc, char *argv[]) { WSADATA wsd; WSAQUERYSET *qs = NULL; char buff[RNR_BUFFER_SIZE]; GUID HostnameGuid = SVCID_INET_HOSTADDRBYNAME; HANDLE hRnr; AFPROTOCOLS afproto[2] = { {AF_INET, IPPROTO_UDP}, {AF_INET, IPPROTO_TCP} }; DWORD dwLength = RNR_BUFFER_SIZE; int ret, i; LPBLOB pvRet = NULL; HOSTENT *hp = NULL; SOCKADDR_IN addr; if (argc != 2) { cout << "wpisz: " << argv[0] << " nazwa_hosta " << endl; return -1; } if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { cerr << "WSAStartup() error no: " << WSAGetLastError() << endl; return -1; } 27 //qs = (WSAQUERYSET *)&buff; qs = (WSAQUERYSET *)buff; memset(qs, 0, sizeof(*qs)); // w pliku dnsquery.vcproj, atrybutowi CharacterSet w tagu Configuration przypisac // wartosc 2, tzn. <Configurations> <Configuration CharacterSet="2” > /////////////////////////////////////////////////////// qs->dwSize = sizeof(WSAQUERYSET); qs->lpszServiceInstanceName = argv[1]; qs->lpServiceClassId = &HostnameGuid; qs->dwNameSpace = NS_ALL; qs->dwNumberOfProtocols = 2; // TCP & UDP qs->lpafpProtocols = afproto; ret = WSALookupServiceBegin(qs, LUP_RETURN_BLOB | LUP_RETURN_NAME, &hRnr); if (ret == NO_ERROR) { ret = WSALookupServiceNext(hRnr, 0, &dwLength, qs); if (ret != NO_ERROR) { if (WSAGetLastError() == WSASERVICE_NOT_FOUND) { cerr <<"No such name found!" << endl; WSALookupServiceEnd(hRnr); return 0; } cerr << "WSALookupServiceNext() error no: " << WSAGetLastError() << endl; } WSALookupServiceEnd(hRnr); } 28 if (qs->lpBlob == NULL) return -1; hp = new HOSTENT [qs->lpBlob->cbSize]; if (!hp) { cerr << "hp on heap failed" << endl; return -1; } //void * memcpy ( void * destination, const void * source, size_t num ); memcpy(hp, qs->lpBlob->pBlobData, qs->lpBlob->cbSize); UnpackHostEnt(hp); for(i=0; hp->h_addr_list[i] ;i++) { memcpy(&addr.sin_addr, hp->h_addr_list[i], hp->h_length); cout << argv[1] << " IP: " << inet_ntoa(addr.sin_addr) << endl; } for(i=0; hp->h_aliases[i] ;i++) cout << "Alias: " << hp->h_aliases[i] << endl; delete [] hp; WSACleanup(); return 0; }//koniec main() 29