Internet - funkce
V této kapitole ukáži pár zajímavých funkcí, které se vám mohou hodit při práci po síti.
Struktura hostent
Struktura hostent
obsahuje informace nalezené pomocí DNS dotazu.
Tuto strukturu, resp. odkaz na ni, vrací například funkce gethostbyname()
a gethostbyaddr()
(viz dále).
Definovaná je takto:
Položka h_addr je definovaná kvůli zpětné kompatibilitě. Dříve totiž bylo možné mít k jednomu DNS záznamu jen jednu IP adresu. Dnes už můžete mít více IP adres (v h_addr_list).
Co je ale zajímavější, a na první pohled to není patrné, tak h_addr_list obsahuje IP adresy jako čísla. Jenomže tyto čísla jsou uloženy jako posloupnost charů. Tato posloupnost je navíc v endianitě vlastní internetu, ne vašemu počítači.
Počet těchto „charů“, tedy bajtů, je dán položkou h_length
.
Pro IPv4 je to vždy 4. Pro IPv6 je to 16 (ne 6, opravdu 16).
Pro převod této posloupnosti na lidsky čitelný text jsem napsal funkci h_addr_to_string()
.
Pro výpis celé struktury hostent
jsem napsal
funkci printHostent()
.
Oboje funkce jsou deklarované v print-hostent.h:
Nejdříve se podívejte na h_addr_to_string()
.
Převádí Ipv4 adresu předanou jako pole charů do textu jako
"127.0.0.1" atp.
Díky tomu, že endianovitost pole charů odpovídá „lidskému“ zápisu, stačí mi každý prvek pole přetypovat na unsigned char a vytisknout v tom pořadí, v jakém je dostanu.
- /*------------------------------------------------*/
- /* 43internetFunkce/print-hostent.c */
- #include <stdio.h>
- #include "print-hostent.h"
- {
- return ip4;
- }
Funkce převede jen IPv4 adresy. Funkci pro převod IPv6 adres si můžete napsat za domácí úkol (použijte %x ;-);
Pole odkazů na aliasy a ip adresy jsou ve struktuře hostent
ukončeny nulovým
odkazem. Z toho vychází podmínky v cyklech while, viz níže.
U tisku adres (while (server->h_addr_list[i])
) tisknu u první položky pole
i hodnotu server->h_addr, abyste mi věřili, že je to opravdu to samé,
co h_addr_list[0]
.
- {
- size_t i;
- i = 0;
- i++;
- }
- server->h_addrtype == AF_INET ? "yes" : "no");
- i = 0;
- h_addr_to_string(server->h_addr_list[i],
- server->h_length));
- h_addr_to_string(server->h_addr,
- server->h_length));
- }
- i++;
- }
- }
- /*------------------------------------------------*/
Funkce gethostbyname() a gethostbyaddr()
V dalším příkladu uvidíte použití funkce gethostbyname()
,
která vrací na základě DNS jména informace o doméně. Dále funkci
gethostbyaddr()
, která vrací tytéž informace,
ale na základě IP adresy.
Jak uvidíte, nevracejí funkce vždy stejné informace, ikdyž je použijete na doménu a její IP adresu.
Funkce gethostbyaddr()
má jako první argument
odkaz na strukturu struct in_addr
(pro IPv4).
Druhým argumentem je délka této struktury (sizeof(struct in_addr)
) a posledním
argumentem typ adresy, který je pro IPv4 AF_INET
(pro IPv6 AF_INET6
).
Pro připomenutí ještě ukáži definici struktury in_addr
:
Podívejte se, jak pomocí memcpy()
přesouvám bajty z
h_addr_list (z pole 4 bajtů) do s_addr (typu uint32_t).
(Obě části paměti zabírají 32 bitů). Tímto způsobem si bajty zachovají správnou
endianovitost.
Poslední nová funkce v příkladu je inet_ntoa()
.
Tato funkce dělá v podstatě to samé, co moje funkce h_addr_to_string()
,
jen dostává jako argument strukturu struct in_addr
.
- /*------------------------------------------------*/
- /* 43internetFunkce/hostname.c */
- #include <stdio.h>
- #include <string.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include "print-hostent.h"
- {
- }
- {
- struct in_addr addr;
- usage();
- }
- server = gethostbyname(argv[1]);
- }
- printHostent(server);
- server = gethostbyaddr(&addr, 4, AF_INET);
- }
- printHostent(server);
- }
- /*------------------------------------------------*/
Všiměte si, že převádím před tiskem addr.s_add endianovitost pomocí ntohl().
Výstup volání ./hostname www.facebook.com
vypadá takto:
gethostbyname(www.facebook.com): **************************** Oficiální jméno hosta: star.c10r.facebook.com Aliasy: www.facebook.com Typ adresy IpV4: yes Délka adresy v bajtech: 4 Seznam adres: 31.13.91.3 (= 31.13.91.3) gethostbyaddr(520968996,4, AF_INET): **************************** Oficiální jméno hosta: edge-star-shv-04-prn2.facebook.com Aliasy: Typ adresy IpV4: yes Délka adresy v bajtech: 4 Seznam adres: 31.13.91.3 (= 31.13.91.3) **************************** inet_ntoa(520968996) = 31.13.91.3
Výsledek volání gethostbyname()
pro www.facebook.com
a gethostbyaddr()
pro IP adresu 173.252.74.22 vracejí trochu rozdílné výsledky.
Doména www.facebook.com je jen alias. V různých částech světa zřejmě dostanete jiné výsledky
(jinou IP adresu, jiné oficiální DNS jméno).
Facebook je příliš velký na to, aby běžel na jednom počítači …
Ještě ukáži pro srovnání výstup s www.google.com:
gethostbyname(www.google.com): **************************** Oficiální jméno hosta: www.google.com Aliasy: Typ adresy IpV4: yes Délka adresy v bajtech: 4 Seznam adres: 173.194.116.242 (= 173.194.116.242) 173.194.116.243 173.194.116.244 173.194.116.240 173.194.116.241 gethostbyaddr(2915202290,4, AF_INET): **************************** Oficiální jméno hosta: prg02s11-in-f18.1e100.net Aliasy: Typ adresy IpV4: yes Délka adresy v bajtech: 4 Seznam adres: 173.194.116.242 (= 173.194.116.242) **************************** inet_ntoa(2915202290) = 173.194.116.242
K funkcím gethostbyname()
a gethostbyaddr()
existují i reentrantní, MT-Safe verze, které mají ovšem
trochu jiné deklarace. Více se dočtete v manuálových stránkách.
K funkcím gethostbyname()
a gethostbyaddr()
existují novější alternativy – getaddrinfo()
a getnameinfo()
. Hezký příklad na tyto funkce
najdete wikipedii.
Funkce getservbyname() a getservbyport()
Tyto funkce vracejí informace nalezené v souboru /etc/services
ve struktuře
struct servent
:
Protokol může být "tcp" nebo "udp" (nebo i nějaký jiný, podívejte se do /etc/services), nebo NULL. V takovém případě se najde záznam bez ohledu na protokol.
Zvážení, nakolik jsou tyto funkce užitečné, nechám na vás. Informace získané ze souboru /etc/services jsou informace o defaultních nastaveních, realita může být jiná. Nalezená služba nemusí na vašem počítači vůbec běžet. A na jiném stroji může běžet pod jiným portem atd.
Příklad:
- /*------------------------------------------------*/
- /* 43internetFunkce/getserv.c */
- #include <netdb.h>
- #include <stdio.h>
- {
- srt = getservbyname("mysql", NULL);
- ntohs(srt->s_port), srt->s_proto);
- srt = getservbyport(htons(3306), NULL);
- ntohs(srt->s_port), srt->s_proto);
- }
- /*------------------------------------------------*/
Výstup z programu:
Name = mysql, port = 3306, protocol = tcp Name = mysql, port = 3306, protocol = tcp
Funkce gethostname()
Funkce gethostname()
vrátí jméno vašeho počítače.
Příklad:
- /*------------------------------------------------*/
- /* 43internetFunkce/gethostname.c */
- #include <stdlib.h>
- #include <unistd.h>
- #include <limits.h> /* HOST_NAME_MAX */
- #include <stdio.h>
- #include <errno.h>
- {
- }
- }
- /*------------------------------------------------*/
Výstup z programu:
hostname = linux-xigc.site
Jak vidíte, jméno mého počítače není nijak nápadité. Nechal jsem takové, jaké mi bylo nabídnuto během instalace.
Pokud si projdete manuálové stránky ke zde probraným funkcím, najdete odkazy na další a další zajímavé (i nezajímavé) funkce.