Protokol Internetu (IP) ma za zadanie zajecie sie trzema waznymi sprawami w problemie przesylu danych sieciami. Sa to :
Moduly zajmujace sie przesylaniem wykorzystuja przesylany z kazdym pakietem danych (ang. datagram) naglowek protokolu IP (ang. IP Header) do przesylania danych pomiedzy stacjami zrodlowa i docelowa. Wiadomosci zawarte w naglowku IP sa rowniez wykorzystywane przy dzieleniu i laczeniu pakietow danych podczas przesylania.
Moduly przesylajace sa niezbedna czescia kazdej jednostki wchodzacej w sklad sieci i z tego powodu sa ustalone pewne reguly odnosnie interpretacji adresow i dzielenia-laczenia pakietow. Moduly takie (w szczegolnosci bramy sieciowe) maja zaimplementowane funkcje pomagajace podjac decyzje o dalszej drodze pakietu.
IP traktuje kazdy pakiet, ktory przetwarza jako calkowicie niezalezny.
IP jest zawodnym protokolem. Nie sprawdza poprawnosci danych. Jedynym kryterium pozwalajacym sprawdzic poprawnosc przesylania jest suma kontrolna naglowka umieszczona w nim (pole check). Jezeli w trakcie transmisji zostal odkryty blad to pakiet jest niszczony przez stacje, ktora wykryla niezgodnosc. W przypadku bledu nie ma zadnych powtorek transmisji i kontroli przeplywu danych.
Deklaracja struktury naglowka w Linuxie jest umieszczona w pliku
/include/linux/ip.h
. Wyglada ona nastepujaco:
struct iphdr { __u8 ihl:4, version:4; __u8 tos; __u16 tot_len; __u16 id; __u16 frag_off; __u8 ttl; __u8 protocol; __u16 check; __u32 saddr; __u32 daddr; };
A oto schemat i wyjasnienia znaczen poszczegolnych pol:
0 | 1 | 2 | 3 | ||||||||||||||||||||||||||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 |
Version | IHL | Type Of Service | Total Length | ||||||||||||||||||||||||||||
Identification | Flags | Fragment Offset | |||||||||||||||||||||||||||||
Time To Live | Protocol | Header Checksum | |||||||||||||||||||||||||||||
Source Address | |||||||||||||||||||||||||||||||
Destination Address | |||||||||||||||||||||||||||||||
O | P | T | I | O | N | S |
Pole w strukturze iphdr: version
Wersja formatu naglowka IP. W linuxie zaimplementowano wersje 4, wersja 6 jest w przygotowaniu.
Pole w strukturze iphdr: ihl
Dlugosc naglowka IP (ang. Internet Header Lenght) wyrazona w 32 bitowych slowach. Wazne jest to, ze minimalna wartosc tego pola to 5.
Pole w strukturze iphdr: tosPole to jest uzywane do przechowywania czysto abstrakcyjnych wartosci majacych podniesc jakosc obslugi pakietu. Niektore sieci moga honorowac ustawione tu bity a pozostale nie. Znaczenie bitow jest nastepujace:
Pole w strukturze iphdr: tot_len
Calkowita dlugosc pakietu wlacznie z naglowkiem i danymi (w bajtach). 16 bitow pozwala na przesylanie maksymalnie 65,535 bajtow. Takie pakiety praktycznie nie sa przesylane w sieci. Standard IP wymaga, aby wszystkie stacje mogly przetwazac pakiety o dlugosci 576 bajtow. Liczba ta bierze stad, ze dane sa zwykle dzielone na pakiety o dlugosci 512 bajtow, 60 pozostalych to dlugosc maksymalnego naglowka IP i zostaja dodatkowe 4 bajty marginesu dla innych protokolow. Najczesciej spotykana dlugoscia naglowka IP jest 20 bajtow.
Pole w strukturze iphdr: id
Wartosc ta jest ustawiana przez nadawce. Ma za zadanie pomoc w identyfikacji fragmentow przy scalaniu pakietow.
Pole w strukturze iphdr: Pole nie wystepuje w strukturze iphdr, ale 3 pierwsze bity pola frag_off sa tak walsnie traktowane.
Rozne flagi kontrolne:
Pole w strukturze iphdr: frag_off
To pole okresla, gdzie w oryginalnym pakiecie powinien byc umieszczony dany fragment. Jednostka tutaj jest 8 bajtow (64 bity). Pierwszy fragment ma wartosc ofsetu zero.
Pole w strukturze iphdr: ttl
To pole okresla maksymalny czas przebywania pakietu w sieci. W momencie gdy to pole osiagnie wartosc zero pakiet danych musi zostac zwrocony. To pole jest modyfikowanie w czasie przesylania komunikatu w sieci. Jednostka sa tu sekundy, ale kazda z przetwarzajacych pakiet stacji ma obowiazek zmniejszyc ja o co najmniej jeden (nawet gdy przetwarzanie zajelo mniej czasu). Dzialanie to ma spowodowac wyeliminowanie pakietow niemozliwych do dostarczenia.
Pole w strukturze iphdr: protocol
To pole okresla, ktory protokol zostal uzyty na wyzszym poziomie w przetwarzaniu danych pakietu.
Pole w strukturze iphdr: check
Suma kontrolna naglowka danych IP. Poniewaz naglowek moze sie zmieniac, suma jest obliczana w kazdym z miejsc w sieci, do ktorego dotal pakiet.
Pole w strukturze iphdr: saddr
Adres nadawcy pakietu.
Pole w strukturze iphdr: daddr
Adres odbiorcy pakietu.
Pole w strukturze iphdr: W Linuxie osobna struktura.
Dodatkowe informacje o pakiecie danych. Jest to opcjonalna czesc naglowka protokolu IP. Najczesciej nie jest ona
dolaczana do pakietu. W Linuxie reprezentowana jest przez strukture options, zaimplementowana w pliku
/include/linux/ip.h
.
Adres w Internecie zajmuje 32-bity i sklada sie z identyfikatorow sieci i stacji. Kazda stacja w sieci musi miec jednoznacznie wyznaczony swoj internetowy adres. Kazdy internetowy adres moze miec jedna z trzech postaci przedstawionych na schemacie:
Klasa A
7 | b | i | t | o | w | 2 | 4 | b | i | t | y | ||||||||||||||||||||
0 | identyfikator sieci | identyfikator stacji |
Klasa B
1 | 4 | b | i | t | o | w | 1 | 6 | b | i | t | o | w | ||||||||||||||||||
1 | 0 | identyfikator sieci | identyfikator stacji |
Klasa C
2 | 1 | b | i | t | o | w | 8 | b | i | t | o | w | |||||||||||||||||||
1 | 1 | 0 | identyfikator sieci | identyfikator stacji |
Jak latwo zauwazyc adesy klasy A sa uzywane w sieciach zlozonych, w ktorych przypada wiele stacji na pojedyncze sieci, podczas gdy adresy klasy C sa odpowiednie dla sieci, ktore maja stosunkowo malo stacji.
Adresy internetowe sa zazwyczaj zapisywane jako czworki liczb dziesietnych rozdzielonych kropkami. Kazda liczba dziesietna odpowiada jednemu bajtowi 32-bitowego adresu (na przyklad 148.255.4.13).
Identyfikatory sieci sa wyznaczane przez upowazniona do tego instytucje, ale identyfikatory stacji sa wyznaczane indywidualnie przez administratora sieci. Daje to mozliwosc przeznaczenia kilku najbardziej znaczacych bitow identyfikatora stacji na tzw. identyfikatory sieci wewnetrznych. Ta wlasciwosc powoduje pojawienie sie jeszcze jednego poziomu w hierarchii adresow w Internecie:
Rozdrabnianie danych jest niezbedne gdy sieci lokalne, przez ktore musi przejsc pakiet aby osiagnac
cel, nie pozwalaja na
przejscie calego pakietu jednorazowo. Z pojeciem tym zwiazana jest wielkosc
maksymalnej jednostki przeplywu danych w sieci (ang.
Maximum Transmission Unit - MTU). Pakiet przesylany siecia moze miec ustawiona flage DF (ang. Don't Fragment) i
wtedy pakiet w zadnym wypadku nie moze zostac podzielony. Jezeli przez to pakiet nie moze byc
dostarczony, to powinien
zostac zniszczony, a nadawca natychmiast poinformowany o zaistnialej sytuacji. Poniewaz rozdrobnione dane musza zostac
scalone przez odbiorce, wartosci jednoznacznie identyfikujace dane sa przekazywane w polu id
(ang. Identification).
Pozycja pojedynczego fragmentu w calym rozdrobnionym pakiecie danych jest przekazywana w polu frag_off
(ang.
Fragment Offset). Pierwszy fragment pakietu ma offset 0. Ostatni fragment ma ustawiona flage MF (ang. More Fragments)
na 0.
Struktury sluzace do przechowywania fragmentow pakietow sa zdefiniowane w pliku
/include/net/ip.h
.
Sa tam
zaimplementowane dwie wazne i proste struktury:
ipfrag
(fragment pakietu) ipq
(kolejka fragmentow pakietu). Budowa tych struktur wyglada nastepujaco:
struct ipfrag { int offset; /* offset fragmentu w pakiecie */ int end; /* ostatni bajt danych w pakiecie */ int len; /* dlugosc tego fragmentu */ struct sk_buff *skb; /* oryginalnie odebrany fragment */ unsigned char *ptr; /* oryginalny fragment danych */ struct ipfrag *next; /* wskazniki polaczeniowe */ struct ipfrag *prev; }; struct ipq { unsigned char *mac; /* wskaznik na naglowek sprzetowy */ struct iphdr *iph; /* wskaznik na naglowek IP */ int len; /* calkowita dlugosc rozdrobnionego pakietu */ short ihlen; /* dlugosc naglowka IP */ short maclen; /* dlugosc naglowka sprzetowego */ struct timer_list timer; /* ile czasu pozostalo do przeterminowania fragmentow */ struct ipfrag *fragments; /* lista polaczonych fragmentow */ struct ipq *next; /* wskazniki polaczeniowe */ struct ipq *prev; struct device *dev; /* Urzadzenie do wysylania informacji o bledzie */ };
Funkcje obslugujace fragmentacje sa zaimplementowane w pliku
/net/ipv4/ip_fragment.c
. Jest tam tez zadeklarowany
globalny wskaznik na wszystkie kolejki fragmentow - ipqueue
.
Organizacja przechowywania pakietow w Linuxie wyglada nastepujaco:
ip_frag_create()
: DEFINICJA: static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr) WYNIK: NULL w przypadku braku pamieci wskaznik na zaalokowany fragment gdy wszystko poszlo dobrze
Allokuje pamiec i wypelnia strukture ipfrag
przechowujaca fragment pakietu.
ip_find()
: DEFINICJA: static struct ipq *ip_find(struct iphdr *iph) WYNIK: wskaznik na odpowiednia kolejke (jezeli istnieje) NULL w przypadku bledu
Przechodzi po kolejce ipqueue
i znajduje strukture ipq,
ktora ma ta sama wartosc w polach id, protocol, saddr,
daddr
co naglowek przekazany jako parametr wywolania. Jezeli nie ma takiej kolejki to zwraca NULL.
ip_free()
: DEFINICJA: static void ip_free(struct ipq *qp) WYNIK: nie ma
Usuwa i niszczy kolejke ipq
przekazana w parametrze. To jest wywolywane w przypadku przetworzenia i scalenia pakietu,
ale takze gdy uplynal "czas zycia" pakietu.
ip_expire()
: DEFINICJA: static void ip_expire(unsigned long arg) WYNIK: nie ma
Wywolywana gdy pakiet sie "przeterminowal". Usuwana jest odpowiednia struktura ipq
i wysylany komunikat za pomoca
protokolu bledu ICMP.
ip_create()
: DEFINICJA: static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev); WYNIK: NULL w przypadku braku pamieci wskaznik na stworzona strukture ipq gdy wszystko bylo w porzadku
Tworzy nowa kolejke ipq
dla nowego pakietu danych.
ip_done()
: DEFINICJA: static int ip_done(struct ipq *qp) WYNIK: 1 gdy wszystkie fragmenty sa juz w kolejce 0 wpp.
Sprawdza, czy sa juz wszystkie fragmenty pakietu w kolejce ipq.
ip_glue()
: DEFINICJA: static struct sk_buff *ip_glue(struct ipq *qp) WYNIK: wskaznik na bufor ze sklejonym pakietem NULL gdy doszlo do bledu
Funkcja skleja wszystkie fragmenty umieszczone we wskazanej kolejce ipq
w jeden pakiet danych i usuwa kolejke.
ip_defrag()
: DEFINICJA: struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev) WYNIK: NULL w przypadku bledu i gdy pakiet zostal umieszczony w kolejce wskaznik na bufor ze sklejonymi fragmentami gdy mozna bylo je skleic
Funkcja przetwarza przekazany fragment. Jezeli byl to pierwszy fragment
pakietu, to tworzona jest nowa kolejka ipq
. Jezeli
taka kolejka juz istnieje, to dodajemy fragment do listy. Jezeli lista jest
pelna, to sklejamy wszystko w jeden pakiet i zwracamy
wskaznik na niego, wpp. zwracamy NULL.
ip_fragment()
: DEFINICJA: void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag) WYNIK: nie ma
Funkcja jest wywolywana gdy trzeba podzielic pakiet na fragmenty. Funkcja w petli while
dzieli pakiet i wysyla
opakowane fragmenty.
/net/ipv4/ip_input.c
.
ip_rcv()
: DEFINICJA: int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) WYNIK: 0 gdy wyszystko w porzadku <0 gdy zostal wykryty bladJest to funkcja wywolywana przez handler interfejsu sprzetowego sieci i standardowo obsluguje wszystkie nadchodzace pakiety.
Jako parametry wejsciowe funkcja otrzymuje min. wskaznik na bufor z danymi pakietu. Z tego parametru funkcja wyluskuje sobie wskaznik na naglowek protokolu IP (w bloku deklaracji zmiennych lokalnych).
W pierwszej kolejnosci funkcja wychwytuje i niszczy wyszystkie fragmenty oznaczone jako wersja 6-ta protokolu IP.
Nastepnie sprawdza czy nie ma bledu w naglowku tzn. czy jest to wersja 4 IP, czy dlugosc bloku nie jest mniejsza od zadeklarowanej dlugosci naglowka i czy naglowek jest najmniej dlugosci 5 (uwaga: w 32-bitowych slowach - patrz definicja naglowka). Jezeli zostal wykryty jakis blad, to pakiet jest niszczony.
Rozpatrywane sa takie przypadki: pakiet jest dla naszej stacji, pakiet jest
rozglaszany (ang. broadcast), dla grupy do ktorej nalezymy, lub dla innej stacji.
Jezeli pakiet jest dla nas, to wykonywane jest sprawdzanie czy dany pakiet
jest podzielony i jesli tak to wywolywane jest scalanie (funkcja
ip_defrag()
). Jezeli scalanie nie bylo potrzebne lub dalo w
wyniku poprawny pakiet, to jest on przekazywany do wszystkich handlerow
protokolow wyzszej warstwy (czyli np. tcp_rcv()
lub
udp_rcv()
).
Jezeli potrzebne jest dalsze przekazanie pakietu, to
generowane sa nowe sumy kontrolne dla naglowka scalonego pakietu i
wywolywane jest przekazanie (funkcja ip_forward()
).
/net/ipv4/ip_input.c
- interfejs wejsciowy protokolu IP
/net/ipv4/ip_fragment.c
- funkcje dzielace i scalajace pakiety IP /include/linux/ip.h
- definicje i deklaracje struktur naglowka protokolu IP /include/net/ip.h
- deklaracje struktur przechowujacych pakiety sk_buff
. W przypadku
odbierania pakietu stukture ta allokuje handler interfejsu sprzetowego, a w
przypadku wysylania modul implementacji gniazd. Jest to bardzo zlozona
struktura, zawierajaca m.in. wskazniki na naglowki wszystkich protokolow
uzytych do przetworzenia danych. Struktury te sa kolejkowane w specjalnych
kolejkach zwiazanych z gniazdami. Oczywiscie zdarza sie, ze protokol IP
zmuszony jest podzielic pakiet i wtedy rowniez musi zaallokowac struktury
sk_buff
dla wszystkich fragmentow.