Lihtsa võrguanalüsaatori ehitamine
Ilmselt on mõistlik tutvust teha Ethereali nimelise programmiga (võib kasutada ka mõnda teist võrguanalüsaatorit, näiteks tcpdump), mille abil tasuks uurida nii "sisevõrgu" masinasse tulevat (ning ehk ka väljuvat) liiklust kui ka seda liiklust, mis toimub kaablimodemi ning NAT'iva routeri vahel.
Sisevõrgus olevasse masinasse saabuvat liiklust saab analüüsida sisevõrgu masinas endas, kaablimodemi ning routeri vahelise liikluse analüüsimiseks on kõige lihtsam laenata või osta HUB (kindlasti hub, mitte switch), mille abil siis ühendada sellesse võrku veel üks seade, mis kuulab seda liiklust pealt.
Testimiseks on kõige lihtsam hankida ligipääs mõnesse Internetis asuvasse Unixilaadsesse süsteemi (paremal puudumisel võib ju muidugi ka naabrimees või keegi teine oma lauaarvutist üritada ühenduda), mille aadress (ma mõtlen reaalne interneti aadress) on teada. Teadaolev Internetis asuva süsteemi aadress anda etherealile filtriks kujul ip.addr == aadress (see konstruktsioon määrab filtrisse nii sellelt aadressilt tulevad kui ka sellele aadressile saadetavad paketid). Kaval on Etherealile öelda, et kõik paketid, mis püütakse, ka kohe välja näidataks (loomulikult on sellisel juhul mõistlik, kui võrgu peal on nii vähe liiklust kui võimalik).
Olles sedasi analüsaatori püsti saanud (ahjaa promisc moodis (sellisel juhul edastab võrgukaart OSile ka selle liikluse, mis ei ole talle mõeldud, vajalik kaablimodemi ja routeri vahelise liikluse pealt kuulamiseks) kuulamiseks on reeglina vaja superkasutaja õigusi), tuleks luua väljastpoolt ühendus oma välisaadressi sellesse porti, kus me eeldame teenust olevat. Kõige lihtsam on seda teha telneti abil: telnet 1.2.3.4 1234
, kus 1.2.3.4
on IP aadress ning 1234
on vastav TCP port.
Algatuseks on mõistlik kuulata teenust pakkuvast masinast - kui välisilmast ühendust luues filtrisse ühtegi paketti ei tulnud, on ilmselge, et viga tuleb otsida routerist(vt. ka allapoole nn. "keerulisem olukord"). Kui aga ühendus ilmub, tuleb hakata analüüsima, mis siis valesti on.
Et asjatundmatu kasutaja ei pruugi esimese hooga Ethereali väljundist suurt midagi aru saada, siis toome siinkohal ühe pisikene näite õnnestunud ühendusest (ehk siis... nõnda peavad asjad olema, kui ei ole, on analoogia põhjal ilmselt üsna lihtne oletada, mis on valesti):
Olukord on järgmine: võrgu väline (reaalselt eksisteeriv) interneti aadress on 217.159.159.181
, millel vastab router, milles on TCP/666 DNAT'itud "sisevõrgus" asuva masina, aadressiga 192.168.2.20
, pordile TCP/22, millelt vastab SSH. Selle teenusega üritatakse ühendust võtta süsteemist aadressiga 194.204.19.34
järgmiselt:
wookie@piixus:~$ telnet 217.159.159.181 666 Trying 217.159.159.181... Connected to 217.159.159.181. Escape character is '^]'. SSH-2.0-OpenSSH_3.9p1 ^] telnet> quit Connection closed.
Sisevõrgus asuva masina seisukohalt näeb ühendus välja järgmine:
ISP ning minu routeri vahel toimus samal ajal aga järgmine:
Olulised on siinkohal kolm esimest paketti:
Iga TCP ühendus algab ühenduse alustaja poolt saadetud [SYN] paketiga. Me märkame, et sisevõrgu masina jaoks on paketi sihtaadress (destination adress) 192.168.2.20
, kuid teiselt pildilt näeme, et tegelikult saabus pakett muidugi aadressile 217.159.159.181
- router transleeris paketi sihtaadressi selliselt, et see sai edasi liikuda meie privaatvõrgu aadressile, samuti me märkame, et antud juhul jättis router paketi lähteaadressi (source address) muutmata. Samasugust transleerimist võime tähele panna pordi numbritega - routerisse saabus pakett pordile TCP/666, kuid sisevõrgu masinasse pordile TCP/22 (ssh).
Kuna [SYN] pakett saabus antud juhul õige masina õigesse porti (sellisesse, mida mõni teenus kuulab), vastab meie masin [SYN, ACK] paketiga, antud juhul aadressile 194.204.19.34
(sealt ju ühendus tuli). Nüüd on äärmiselt oluline uurida, kas see pakett ruuterist 194.204.19.34
aadressile välja ikka saadeti. Vaatame välise ühenduse pilti ning näeme, et router saatis [SYN, ACK] paketti aadressilt 217.159.159.181
aadressile 194.204.19.34
, samal ajal kui meie sisevõrgus olev masin hoopis aadressilt 192.168.2.20
aadressile 194.204.19.34
- loogiline, pakett peab antud juhtumil väljuma routeri source aadressiga, ehk siis reaalselt internetis eksisteeriva aadressiga. Kui paketi lähteaadress oleks teistsugune, näiteks 192.168.2.20
, ei oleks ühenduse loomine õnnestunud, sest ühendust algatava masina jaoks oleks see olnud kui SYN,ACK pakett mingilt täiesti tundmatult aadressilt, millega ta pole kunagi üritanud suhelda. Seda, et meie routeris 217.159.159.181
'st saab maagiliselt 192.168.2.20
, 194.204.19.34
ei tea ega saa ka kunagi teadma. Samuti, täpselt samasugune transleerimine toimub pordinumbritega - sisevõrgu masin vastab pordist (source port) TCP/22 (ssh), kuid routerist väljuv pakett lähtub pordist TCP/666.
Kui siiamaale juba asjad õnnestusid, siis üldiselt õnnestub ka TCP ühenduse loomiseks vajaliku kolmanda paketi (ühenduse algataja poolne vastus [ACK] "serveri" [SYN, ACK]'le) saatmine. Me märkame, et selle paketiga käitutakse sarnaselt päris esimesele paketile.
Sellest hetkest alates on ühendus loodud ning järgneb juba data: Server (meie näites siis sisevõrgus olev masin) ütleb: SSH-2.0-OpenSSH_3.9p1
. Mida kliendis jooksev applikatsioon sellega peale hakkab, on juba tema enda mure - meie näites kasutatav telnet ei oska sellega mitte mütsigi teha, kuid kuna me juba nägime serveri poolset vastust, oleme me veendunud, et ühendust on võimalik luua ning paneme telneti hoopis kinni (mis toimub ühenduse sulgemisel võib igaüks ise jälgida, uurides kolme viimast paketti). Ahjaa.. küsite, et mida kuradit teeb siis viies, [ACK] pakett? See on lihtsalt kliendi poolne vastus, et ta sai eelmises paketis saadetud teate (SSH-2.0-OpenSSH_3.9p1
) kenasti kätte.
Ma usun, et igaüks teab aga igaks juhuks kordame veel üle, et iga sellise NAT'itud ühenduse peale teeb router kuhugile oma mälus asuvasse tabelisse kirje, milles on kirjas, mida täpselt muudeti ning oskab selle järgi vastassuunas liikuvate pakettide välju vastupidiselt muuta, et kõik ikka õnnelikud oleks - kuidas see käib, pole antud hetkel meie asi, lihtsalt jätame meelde, et selline tabel kuskil routeri kõhus on.
Tähelepanelik lugeja kindlasti märkab, et suunal klient (kuskil interneti avarustes asuv purk) -> server (meie sisevõrgu masin) muudeti ainult pakettide sihtaadressi (destination address) ning suunal server -> klient ainult paketi lähteaadressi (source address). Enamik selliseid pordisuunamisi töötab selliselt. Niisuguses lahenduses, kus sisevõrgust interneti poole suunduvate pakettide lähteaadressi tuleb nii ehk naa transleerida, pole mõtet vastupidise NAT'i korral välisilmast saabuvate pakettide lähteaadressi muuta.
Samas... eksisteerib ka keerulisem olukord - router muudab nii siseneva paketi lähte- kui ka sihtaadressi. Sellisel juhul jääb meie sisevõrgus olevale serverile mulje nagu ta suhtleks routeri endaga. Niisugusel juhul sisevõrgus filter ip.addr == ip_aadress ei kõlba (sest sisevõrgus ju mitte keegi ei suhtle selle välise aadressiga) ning tuleks asendada keerulisema filtriga, minu puhul siis näiteks: ip.addr == 192.168.2.254
(192.168.2.254
on minu ruuteri sisevõrgu aadress, me püüame liiklust, mida peetakse selle seadmega) või suisa ip.addr == 192.168.2.254
&& tcp.port == 22 (TCP liiklus, mida peetakse routeriga, mille lähte- või sihtport on 22). Igaks juhuks ühest sellisest ühendusest pilt kah (vaadatuna siis sisevõrgu masina poolt - väljastpoolt ei muutu midagi).
Üldiselt peaks nendest teadmistest piisama, et lihtsamate pordisuunamise probleemide põhjuseid diagnoosida. Tavaliselt, kui sellist õnnestunud ühendust võrrelda ebaõnnestunud ühenduse korral püütud pakettidega, hakkab viga vähegi tähelepaneliku süvenemise korral ise silma ning parandamine on tavaliselt juba triviaalne tegevus. Keerukamate probleemide korral võib muidugi ka Õpetatud Kogu[tm] tunde või suisa päevi ladinakeeles päid vangutada, et välja mõelda, mis siis ikkagi peetis on, kuid praktika näitab, et enamik probleeme on tegelikult lihtsad.
Tjah, kindlasti tasub meeles pidada, et Ethereal oskab püütud pakette salvestada (jah, just nimelt File::Save) - sellised ethereali failid võivad probleemide lahendamisel vägagi abiks olla, mistõttu maksab selliste hädade korral abiküsimise kõrvalt ka mõni niisugune Ethereali fail kätesaadavaks teha. Et kõik saaks ise uurida, siis juurde ka antud näites kasutatud ühenduste salvestused: http://rio.ee/~wookie/tcp-yhendus http://rio.ee/~wookie/tcp-yhendus-valine http://rio.ee/~wookie/tcp-yhendus-full-nat
P.S. Jah ma tean küll, et antud juhul ei ole routerist rääkimine päris korrektne, sest klassikaline router ei muuda edastatavates pakettides ei IP aadresse ega pordi numbreid, kuid antud juhul, kuna probleem on selgelt seotud NAT'iga, tundus sõna router kasutamine otstarbekam, sest NAT'iv router või NAT'i purk vms. oleks lihtsalt kohutavalt kohmakas. Seega lugege sõna "router" antud juhul kui "see router selles konkreetses seadistuses võrguaadresse transleerimas (NAT)".
P.P.S. Ehki meie kasutasime näites SSH teenust, mis peale ühenduse loomist ise mingit mula välja hakkab ajama, ei prugi sellist igaühel käepärast olla. Sageli on tarvis testida näiteks WWW (TCP/80) teenuse töötamist, mille puhul server jääb peale ühenduse loomist ootama, et talle mõni käsk antaks. Sellisel juhul on mõistlik telneti sisse peale ühenduse saamist kirjutada suvaline esimesena meelde tulev vandesõna või roppus ning taguda paar korda enterit. WWW server peab vastama HTML'iga, mis tahab meile öelda, et 501 Method Not Implemented või midagi muud sama roppu.