Section author: Ivan Ivakić, Vedran Miletić

Modularni usmjerivač Click

Click je softver koji omogućuje izgradnju usmjerivača korištenjem gotovih modula. Omogućuje veliku slobodu u konfiguraciji i specificiranju načina usmjeravanja i prosljeđivanja paketa. Click podržava realizaciju preklopnika, “običnog” usmjerivača, usmjerivača koji vrši prevođenje mrežnih adresa (Network Address Translation, NAT), vatrozida ili bilo kojeg drugog softverskog entiteta koji obrađuje pakete. S obzirom na dobru unutrašnju strukturu sloboda pri konfiguriranju je velika čime se pruža mogućnost detaljnog specificiranja raznih protokola te je pogodan za simuliranje standardnih, kao i eksperimentalnih konfiguracija.

Click je napisan u programskom jeziku C++ i dostupan je kao otvoreni kod pod modficiranom MIT licencom. Detaljni opis Clicka dan je u doktoratu Eddieja Kohlera pod naslovom The Click Modular Router. Mi se internom implementacijom Clicka nećemo detaljnije baviti, već ćemo se fokusirati na elemente koje on nudi i njihovu konfiguraciju. Programski jezik koji se koristi za definiranje same konfiguracije je vlastiti jezik Click, a datoteke koje sadrže konfiguraciju imaju ekstenziju .click.

Click pokrećemo naredbom click i navođenjem konfiguracijske datoteke. Primjerice, za konfiguracijsku datoteku mojrouter.click naredba bi bila oblika:

$ click mojrouter.click

U nekim konfiguracijama Click će se nastaviti izvoditi sve dok ga ne prekinemo. Naime, radi se o usmjerivaču koji je osmišljen da nakon inicijalizacije konfiguracije radi usmjeravanje i prosljeđivanje paketa dokle god mu se ne kaže da radi drugačije. Prekid rada Clicka ćemo izvesti kombinacijom tipki Ctrl + C, što terminali često prikazuju kao ^C.

Vlastiti jezik Click

Jezik Click opisuje konfiguracije Click usmjerivača. Radi se o vlastitom jeziku koji nema veze s C++-om u kojem je Click implementiran. Dva su osnovna sintaktička elementa jezika Click: deklaracija i veza.

Deklaracija je oblika:

name :: class(config);

Ovim kodom uvodi se element imena name koji je klase elementa class i ima konfiguraciju config.

Veza je oblika:

name1 [port1] -> [port2] name2;

Ovim kodom povezuje se izlazna vrata port1 elementa name1 s ulaznim vratima port2 elementa name2.

Elementi

Za primjere elemenata uzet ćemo RandomSource (dokumentacija), koji generira slučajne pakete, i Tee (dokumentacija), koji duplicira pakete, analogno naredbi tee na operacijskim sustavima sličnim Unixu (kopira standardni ulaz na standardni izlaz i u datoteku).

Note

Ako ste ispravno instalirali Click, dokumentacija elemenata vam je dostupna i u man stranicama u sekciji 7. Primjerice, za dokumentaciju elementa Tee, naredba je man 7 Tee. Dokumentacija samog Clicka, kao i većine naredbi na operacijskim sustavima sličnim Unixu, dostupna je u sekciji 1 (naredba man 1 click ili samo man click).

Element RandomSource ima obavezan parametar u kojem se navodi duljina paketa. Element Tee ima obavezan parametar u kojem se navodi broj izlaza. Povezivanje izvora paketa duljine 64 bajta i duplikatora paketa s dva izlaza izvest ćemo kodom:

RandomSource(64) -> Tee(2);

Pokušamo li navedeni kod spremiti u datoteku randomsrc-tee.click i pokrenuti u Clicku, dobit ćemo poruku o grešci.

$ click randomsrc-tee.click
foo.click:1: ‘Tee@2 :: Tee’ output 0 unused

Spojimo izlaze elementa Tee na elemente ToDump (dokumentacija), koji zapisuje pakete u formatu pcap, i ToIPSummaryDump (dokumentacija), koji zapisuje informacije o paketima u tekstualnom obliku. Također, ograničimo broj paketa koji će biti generirani od strane elementa RandomSource na 1000.

RandomSource(64, LIMIT 1000) -> t :: Tee(2);
t[0] -> ToDump(paketi.pcap);
t[1] -> ToIPSummaryDump(paketi.txt);

Obzirom da izlaz 0 možemo izravno spojiti, navedeni kod možemo zapisati i na način:

RandomSource(64, LIMIT 1000) -> t :: Tee(2) -> ToDump(paketi.pcap);
t[1] -> ToIPSummaryDump(paketi.txt);

Navedeni kod spremamo u datoteku randomsrc-tee-dump.click i pokrećemo naredbom:

$ click randomsrc-tee-dump.click

Pokretanjem Clicka uočit ćemo da ovaj put nema grešaka te će obje izlazne datoteke biti stvorene i ispunjene sadržajem. Kada Click završi generiranje 1000 paketa i njihovo zapisivanje u obje datoteke, nastavit će se izvoditi (i čekati na nove pakete iz elementa RandomSource) sve dok ga ne prekinemo.

Možemo prekinuti izvođenje Clicka i datoteku paketi.pcap možemo pogledati u Wiresharku, a datoteku paketi.txt u bilo kojem uređivaču teksta ili less-u. Uočit ćemo da naši slučajno generirani paketi nisu IP paketi pa nismo dobili naročito mnogo informacija o njima sa zadanom konfiguracijom elementa ToIPSummaryDump (detaljni pregled informacija koje je moguće ispisati možemo pronaći u dokumentaciji elementa).

Primjeri konfiguracija Click usmjerivača

Note

Primjeri konfiguracija dani ispod preuzeti su s danas nedostupnih službenih stranica Clicka, specifično službenog tutoriala. Također nedostupna dokumentacija elemenata prebačena je na Clickovom wiki na GitHubu.

Primjer 1

Konfigurirajte usmjerivač koji čita pakete iz tcpdump datoteke f1a.pcap i zapišite te pakete u novu tcpdump datoteku f1b.pcap. Pakete pritom nemojte mijenjati ni na kakav način.

Rješenje primjera 1

Element FromDump (dokumentacija) prima dva parametra: prvi je ulazna datoteka, a drugi određenje da se čita do kraja datoteke.

Element ToDump (dokumentacija) je ekvivalent prethodnoj funkciji samo u “obrnutom” smjeru, prvi parametar je izlazna datoteka, a drugi je tip enkapsulacije koja se koristi.

FromDump(f1a.pcap, STOP true) -> ToDump(f1b.pcap, ENCAP IP);

Primjer 2

Konfigurirajte usmjerivač koji će usmjeravati pakete u izlazne datoteke s obzirom na danu tablicu usmjeravanja i pripadajućih odredišta (izlaznih datoteka).

Odredište

Izlazne datoteke

131.0.0.0/8

f2b.pcap

131.179.0.0/16

f2c.pcap

18.0.0.0/8

f2d.pcap

Ostalo

f2e.pcap

Rješenje primjera 2

Element RadixIPLookup (dokumentacija) prima uparene vrijednosti adrese i pripadajuće maske te porta kao parametre. Ponovno čitamo ulaznu datoteku elementom FromDump i zapisujemo pomoću elementa ToDump. Primijetimo kako povezujemo pojedine izlaze elementa RadixIPLookup, kojih ima četiri, s četiri različita elementa ToDump. Indeksi izlaza počinju od 0 te odgovaraju redoslijedu uparenih vrijednosti adrese i izlaznih vrata elementa.

FromDump(f2a.pcap, STOP true)
    -> r :: RadixIPLookup(131.0.0.0/8 0, 131.179.0.0/16 1, 18.0.0.0/8 2, 0/0 3);
r[0] -> ToDump(f2b.pcap, ENCAP IP);
r[1] -> ToDump(f2c.pcap, ENCAP IP);
r[2] -> ToDump(f2d.pcap, ENCAP IP);
r[3] -> ToDump(f2e.pcap, ENCAP IP);

Primjer 3

Dogradite kreirani usmjerivač prethodnog zadatka koji će čitati f3a.pcap datoteku te iz nje kreirati f3f.pcap datoteku poštujući pravila dana u tablici. (Napomena: pripazite na redoslijed provjera te prethodno danu tablicu usmjeravanja.)

Problem

Akcija

Neispravno IP zaglavlje ili checksum

Odbaciti paket

Neispravno TCP zaglavlje ili checksum

Odbaciti paket

Neispravno UDP zaglavlje ili checksum

Odbaciti paket

Neispravno ICMP zaglavlje ili checksum

Odbaciti paket

Istek TTL-a

Generirati pripadajuću ICMP poruku, poslati poruku u f3f.pcap datoteku

Paket duži od 1500 bajtova

Odbaciti paket

Rješenje primjera 3

Novi elementi koje ćemo koristiti su CheckIPHeader (dokumentacija), CheckTCPHeader (dokumentacija), CheckLength (dokumentacija), CheckUDPHeader (dokumentacija), CheckICMPHeader (dokumentacija) i ICMPError (dokumentacija). Uočimo da je ovdje poredak provjera značajan.

FromDump(f3a.pcap, STOP true)
     -> CheckIPHeader
     -> i1 :: IPClassifier(tcp, udp, icmp, -)
     -> CheckTCPHeader
     -> ttl :: IPClassifier(ttl > 0, -)
     -> cl :: CheckLength(1500)
     -> ip :: IPClassifier(dst 131.179.0.0/16, dst 131.0.0.0/8, dst 18.0.0.0/8, -);
  i1[1] -> CheckUDPHeader -> ttl;
  i1[2] -> CheckICMPHeader -> ttl;
  i1[3] -> ttl;
  ttl[1] -> ICMPError(18.26.7.1, timeexceeded, transit)
     -> ToDump(f3f.pcap, ENCAP IP);
  ip[0] ->  ToDump(f3c.pcap, ENCAP IP);
  ip[1] ->  ToDump(f3b.pcap, ENCAP IP);
  ip[2] ->  ToDump(f3d.pcap, ENCAP IP);
  ip[3] ->  ToDump(f3e.pcap, ENCAP IP);

Primjer 4

Nadogradite prethodni primjer tako da brojite koliko je paketa odbačeno iz pojedinih razloga. Odredite:

  1. Broj paketa sa neispravnim IP zaglavljem ili kontrolnim zbrojem

  2. Broj paketa sa neispravnim TCP zaglavljem ili kontrolnim zbrojem

  3. Broj paketa sa neispravnim UDP zaglavljem ili kontrolnim zbrojem

  4. Broj paketa sa neispravnim ICMP zaglavljem ili kontrolnim zbrojem

  5. Broj paketa sa isteklim TTL poljem

  6. Broj paketa duljih od 1500 bajtova

Rješenje primjera 4

Novi elementi koje ćemo koristiti su Counter (dokumentacija), Discard (dokumentacija) i DriverManager (dokumentacija).

FromDump(f4a.pcap, STOP true)
   -> cip :: CheckIPHeader
   -> i1 :: IPClassifier(tcp, udp, icmp, -)
   -> ctcp :: CheckTCPHeader
   -> ttl :: IPClassifier(ttl 0, -) [1]
   -> cl :: CheckLength(1500)
   -> ip :: IPClassifier(dst 131.179.0.0/16, dst 131.0.0.0/8, dst 18.0.0.0/8, -);

i1[1] -> cudp :: CheckUDPHeader -> ttl;
i1[2] -> cicmp :: CheckICMPHeader -> ttl;
i1[3] -> ttl;

ttl[0] -> cttl :: Counter
   -> ICMPError(18.26.7.3, timeexceeded, transit)
   -> ToDump(f4f.pcap, ENCAP IP);

ip[0] -> ToDump(f4c.pcap,  ENCAP IP);
ip[1] -> ToDump(f4b.pcap,  ENCAP IP);
ip[2] -> ToDump(f4d.pcap,  ENCAP IP);
ip[3] -> ToDump(f4e.pcap,  ENCAP IP);

cl[1] -> ccl :: Counter -> Discard;

DriverManager(pause, print >f4drops.txt cip.drops,
   print >>f4drops.txt ctcp.drops,
   print >>f4drops.txt cudp.drops,
   print >>f4drops.txt cicmp.drops,
   print >>f4drops.txt cttl.count,
   print >>f4drops.txt ccl.count);

Primjer 5

Konfigurirajte usmjerivač koji će raditi na isti način kao usmjerivač u primjeru 3, no umjesto da pakete bilježite u datoteke jednostavno ih odbacite. Definirajte element koji će izvršavati provjeru (umjesto simulacije Click usmjerivača koji vrši provjeru).

Rješenje primjera 5

elementclass ErrorChecker {
   input -> cip :: CheckIPHeader
      -> i1 :: IPClassifier(tcp, udp, icmp, -)
      -> ctcp :: CheckTCPHeader
      -> ttl :: IPFilter(drop ttl 0, allow all)
      -> cl :: CheckLength(1500)
      -> output;
   i1[1] -> cudp :: CheckUDPHeader -> ttl
   i1[2] -> cicmp :: CheckICMPHeader -> ttl
   i1[3] -> ttl
}

Definirani element ErrorChecker sada ima jedan ulaz i jedan izlaz te ga možemo koristiti kao i bilo koji drugi element, primjerice:

FromDump(f5a.pcap, STOP true) -> ErrorChecker -> ToDump(f5b.pcap, ENCAP IP);