Řízení IP provozu

v operačním systému LINUX

(verze jádra 2.2.13)


Autoři:
Martin Ramajzl, FAV-IVT, email: ramajzl@students.zcu.cz
Jan Nejman, FAV-IVT, email: nejman@students.zcu.cz
Datum poslední změny 5.12.1999

Obsah dokumentu

Základní informace o řízení IP provozu
Datové struktury pro řízení IP
Popis komunikace s jádrem
Implementace
Použitá literatura

1. Základní informace o řízení IP provozu

Do vlastního řízení IP provozu patří směrování, shapping a ip tunely, případně i jiné.

Shapping - Jedná se službu zajišťující kontrolu nad využitím kapacity daného kanálu. Lze regulovat množství dat, která projdou za daný časový interval zařízením.

Tunely - Jedná se o technologii umožňující zapouzdření paketů do paketů jiného typu.

Směrování - Nejdůležitějším prvkem je pravděpodobně směrování, neb zajišťuje způsob zpracování došlého IP paketu. Rozhoduje o tom, kam bude došlý paket směřovat dál a tedy co se sním stane.

Základem pro směrování je směrovací tabulka, která obsahuje všechny potřebné informace pro správné doručení IP paketů. viz manuálové stránky pro "route". Rozhodování probíhá na základě cílové IP adresy obsažené v IP paketu ( Destination ).

Příklad směrovací tabulky:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
1.0.0.0            *           255.0.0.0         U       0    0      0   eth0
127.0.0.0          *           255.0.0.0         U       0    0      0   lo
Popis významu jednotlivých položek a parametrů je snadno zjistitelný v manuálových stránkách. Celé řízení směrování je tedy pouze otázkou správného nastavení jednotlivých položek této tabulky. Směrovací tabulka se nachází v jádře a vlastní manipulaci s touto tabulkou tedy pochopitelně provádí funkce jádra. Je nutné rozlišit dvě základní činnosti s touto tabulkou a to jednak její přímé použití pro směrování a jednak provádění změn, jako je přidání nebo mazání.

Vlastní směrování - Vlastní směrování obsluhují funkce implementované přímo v jádře systému a popsané v souboru net/ipv4/route.c . Tato funkce zajišťuje celý průběh práce s IP packetem, a to fragmentaci, defragmentaci, porovnání se směrovací tabulkou a následné zpracování - tj. odeslání. Tento proces se tedy děje pouze na straně jádra.

Provádění změn ve směrovací tabulce - Tato operace už nutně vyžaduje součinnost uživatele i jádra. Jsou tedy funkce na straně uživatelské a funkce na straně jádra, které se tímto zabývají.

Zpět na obsah

2. Datové struktury pro řízení IP

Struktura pro přidávání položek do směrovací tabulky:
(definována v include/linux/route.h)
struct rtentry
  {
    unsigned long int rt_pad1;
    struct sockaddr rt_dst; 	/* cílová adresa */
    struct sockaddr rt_gateway;	/* adresa brány */
    struct sockaddr rt_genmask;	/* maska sítě cíle */
    unsigned short int rt_flags;/* flagy - viz. níže */
    short int rt_pad2;
    unsigned long int rt_pad3;
    unsigned char rt_tos;	/* typ služby */
    unsigned char rt_class;	/* třída */
    short int rt_pad4;
    short int rt_metric;	/* metrika */
    char *rt_dev;
    unsigned long int rt_mtu;	/* max. velikost packetu */
    unsigned long int rt_window;/* velikost TCP/IP okna */
    unsigned short int rt_irtt;	/* doba po níž jádro testuje rychlejší spojení*/
  };
Flagy:
(definovány v include/linux/route.h)
RTF_UP		- routování je povoleno
RTF_GATEWAY	- cílem je brána do jiné sítě
RTF_HOST	- cílem je počítač, jinak je cílem síť
RTF_REINSTATE	- po timeoutu znovu vytvoř tabulku
RTF_DYNAMIC	- vytvořeno dynamicky přesměrováním
RTF_MODIFIED	- modifikováno dynamicky přesměrováním
RTF_MTU		- specifické nastavení max. velikosti packetu 
RTF_MSS		- to samé co RTF_MTU - kompatibilita
RTF_WINDOW	- používej velikost okna
RTF_IRTT	- používej IRRT viz výše
RTF_REJECT	- zakazání routování

Popis struktury:
Struktura rtentry je podstatná pro přenos uživatelem zadaných dat do jádra přesněji k funkcím implementovaným v jádře, které tuto informaci dále zpracují a aktualizují příslušně směrovací tabulku. Položky rt_pad1 až rt_pad4 jsou pouze výplně a nemají žádný smysl, pro to se vůbec nemusí vyplňovat, ve struktuře jsou pouze pro zachování zpětné kompatibility. Další položky předpokládají znalost sítí.


schématické znázornění komunikace proces - jádro


Zpět na obsah

3. Popis komunikace s jádrem

Před komunikací s jádrem, je nejprve naplněna struktura rtentry. Komunikace s jádrem nastává až v okamžiku, kdy je otevřen socket do jádra. V paměti se vytvoří datová struktura voláním funkce socket(), obsahující informace potřebné pro komunikaci a ukazatel na tuto strukturu se uloží do tabulky deskriptorů. Aplikaci se vrátí index do této tabulky - deskriptor socketu.

Po otevření socketu se pomocí níže popsané funkce jádra ioctl zadá příslušný příkaz do jádra. Výpis těchto příkazů je uveden níže spolu s ukázkou programové implementace této techniky.

Volání funkce jádra ioctl vytváří rozhraní, umožňující procesům ovládat znaková zařízení, ale není použitelné pro obyčejné soubory. Naopak volání jádra fcntl poskytuje možnost řídit operace na úrovni deskriptoru souboru, nikoliv na úrovni zařízení. Jiné implementace interpretují ioctl pro všechny typy souborů. Každý ovladač zařízení nemusí ovšem podporovat rozhraní všech volání jádra. Například může dovolit uživatelům číst záznamy zapsané jinými ovladači, ale nedovolí jim tyto záznamy zapisovat.

Volání funkce jádra ioctl je zobecněním terminálově specifických volání jádra stty a gtty, které byly k dispozici v dřívějších verzích systému UNIX. Tvoří obecný a universální vstupní bod příkazů specifických pro zařízení a umožňuje tak procesům nastavovat jak charakteristiky technických prostředků, tak programové volby spojené s ovladačem. Konkrétní operace, specifikované voláním ioctl, se mohou od zařízení k zařízení lišit a jsou definovány ovladačem zařízení. Vzhledem k tomu, programy, které používají ioctl, musí vědět, s jakým typem pracují. Je to výjimka z obecného pravidla, podle kterého systém nerozlišuje mezi soubory různých typů. Syntaxe volání jádra je:

ioctl(ds, příkaz, arg);

kde ds je deskriptor souboru, vrácený předchozím voláním jádra, příkaz je požadavek ovladače na vykonání určité akce a arg je parametr (případně ukazatel na strukturu). Formát datové struktury závisí na příkazu. Ovladače mohou buď datovou strukturu arg číst nebo zapisovat, ale vždy jen z/do uživatelského adresového prostoru.

Mezi nejdůležitější příkazy pro řízení IP provozu patří:

1. Volání spojená s routovací tabulkou

SIOCADDRT	-	přidá položku do routovací tabulky 
SIOCDELRT	-	smaže položku v routovací tabulce 
SIOCRTMSG	-	volá routovací systém

2. Volání spojena s protokolem ARP
SIOCDARP	-	smaže položku z ARP tabulky 
SIOCGARP	-	vrátí položku z ARP tabulky 
SIOCSARP	-	nastaví položku v ARP tabulce

3. Volání spojená s protokolem RARP
SIOCDRARP	-	smaže položku z RARP tabulky 
SIOCGRARP	-	vrátí položku z RARP tabulky 
SIOCSRARP	-	nastaví položku v RARP tabulce

4. Volání privátního ioctl
SIOCDEVPRIVATE	-	tyto příkazy jsou určeny pro privátní služby, 
                        jako je například shapping.

Pokud jádro obdrží požadavek na vykonání nějakého příkazu (volání pomocí ioctl), spustí svoji obsluhu, kde se rozhoduje podle volaného příkazu, které funkce má spouštět. Tato funkce zpracuje data přenesená v argumentu funkce ioctl, v našem případě rtentry. Tyto data okopíruje z uživatelského adresového prostoru do prostoru jádra a vloží je do směrovací tabulky, kterou už využívá jádro při přijmutí packetu.
Zpět na obsah

4. Implementace

Vlastní spouštěný program (příkaz) route zajistí hrubé zpracování příkazové řádky, tedy nutnost některých parametrů, jejich správný formát, apod. Následuje zpracování uživatelského vstupu, který vykonává funkce INET_setroute, která se nachází v souboru inet_sr.c

Deklarace funkce INET_setroute:

static int INET_setroute(int action, int options, char **args)

kde action udává, má-li se položka směrovací tabulky přidat či odebrat
options jsou volby nastavení a
args ukazuje na pole argumentů.

Součástí popisované funkce INET_setroute je implementace výše zmiňovaného otevření socketu a zajištění komunikace s jádrem. Ze strany uživatelského rozhraní je toto poslední krok.

Vlastní navázání komunikace s jádrem probíhá takto:

 int skdf = -1;
    /* vytvor socket do jadra*/
    if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 
        perror("socket");
        return (E_SOCK);
    }
    /* parametr socketu - akceptuj změny*/
    if (action == RTACTION_DEL) {
        if (ioctl(skfd, SIOCDELRT, &rt) < 0) { 
            perror("SIOCDELRT");
            close(skfd);
            return (E_SOCK);
        }
    } else {
        if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
            perror("SIOCADDRT"); 
            close(skfd);
            return (E_SOCK);
        }
    }

    /* zavri socket. */
    (void) close(skfd);
Na straně jádra se vyvolá funkce inet_ioctl, která podle jednotlivých příkazů vyvolá jejich obslužné funkce. V těchto funkcích bývá například ověření, má-li uživatel práva pro provedení služby, apod.
Zpět na obsah

5. Použitá literatura

Zpět na obsah