2012. január 31., kedd

Adott program által nyitott port (nem épp hagyományos módszerrel :))

Nemrég szegeztek nekem egy érdekes kérdést az AIX működésével kapcsolatban, ténylegesen, hogy hogyan lehet megtudni, hogy egy program milyen TCP portot tart nyitva.
Persze mondhatnánk, hogy a standard módszer a válasz a kérdésre, miszerint:

- Megnézzük, hogy az adott portot melyik socket címen lehet elérni:
testsystem:root # netstat -Aan |grep LISTEN |grep "\*\.22"
f1000200032b7b98 tcp4       0      0  *.22               *.*                LISTEN
- Majd a socketra ráengedve egy rmsock-ot nyomban meg is tudjuk az eredményt..
testsystem:root # rmsock f1000200032b7b98 tcpcb
The socket 0x32b7808 is being held by proccess 1290348 (sshd).
- Azaz, hogy jelen esetben az sshd fogja a 22es portot.
testsystem:root # ps -fp 1290348
     UID     PID    PPID   C    STIME    TTY  TIME CMD
    root 1290348  475196   0 03:32:57      -  0:00 /usr/sbin/sshd
Na de, itt nem errol volt szó!

A probléma ugyan is az, hogy mi azt szeretnénk tudni, hogy egy program milyen TCP portot fog, nem pedig, hogy egy elérhető portot mely alkalmazás tart nyitva. Ez persze megfordítja az egész kérdést, és a netstat-os lehetőséget is totál megtorpedózza.

Persze mondhatnánk, hogy ott az lsof, az tudja e, de tételezzük fel, hogy nem rendelkezünk ilyen eszközzel, hanem csak az alap AIX-hez adott base toolokkal.. Ez esetben ki mihez nyúlna??

Nos.. Én úgy gondoltam, hogy ha lúd, legalább legyen kövér: Menjünk le kernel szintre, és túrjunk benne könyékig amennyire csak lehet. Nézzük, hogy ez mit is eredményezett esetemben:

Első körben ugye indítsuk el a kdb-t, majd ha már bent vagyunk kapcsoljuk ki a Symbolic name Translation-t, mert engem személy szerint zavarni szokott amikor nem a teljes címet írja ki a kdb, hanem csak egy részét (pvthread+??????)
testsystem:root # kdb
(0)> ns
Symbolic name translation off
Ez után térjünk a lényegre.. Azt ugye tudjuk, hogy most az SSH programról beszélünk, aminek meg mint fentebb láthattuk a PID-je 1290348. Nézzük ez milyen címen tanyázik épp:
(0)> tpid -d 1290348|grep "0  $"
                SLOT NAME     STATE    TID PRI   RQ CPUID  CL  WCHAN
F100070F10023A00  570*sshd     SLEEP 23A099 03C    1         0
Oks.. Akkor ez is megvan . Menjünk tovább.. Tudni kéne, hogy az adott process milyen descriptorokat tart nyitva.. Ezt viszonylag könnyen megnézhetjük a user (u) paranccsal:
(0)> u -f F100070F10023A00 |grep -w fd
   fd      0 fp..F1000714500DAE58 count..00000000 flags. ALLOCATED
   fd      1 fp..F1000714500293E0 count..00000000 flags. ALLOCATED
   fd      2 fp..F1000714503CFE60 count..00000000 flags. ALLOCATED
   fd      3 fp..F100071450926220 count..00000001 flags. ALLOCATED
Ezek közül az egyik címen egy socket referenciának kell lennie, amennyiben az adott program valóban nyitott portot.. Sajna nem tudhatjuk pontosan melyik az, így muszáj ezen végigmennünk egyesével.. Mázlimra csak 4 van, így ez nem olyan nagy probléma..
(0)> file F1000714500DAE58 |grep -w ^SOCKET
(0)> file F1000714500293E0 |grep -w ^SOCKET
(0)> file F1000714503CFE60 |grep -w ^SOCKET
(0)> file F100071450926220 |grep -w ^SOCKET
SOCKET......... F1000200032B7808
BINGO.. Nézzük mit találtunk.. Első körben menjünk biztosra, és ellenőrizzük vissza, hogy a socket melyik process-hoz van rendelve
(0)> sock F1000200032B7808 |grep proc
proc/fd:  315/3
A 3as fd az még fentebbről ismerős lehet, de hogy kerül ide a 315? Egyszerűen úgy, hogy a socketet nyitáshoz is kell egy thread, ergo valószínű, hogy a 315ös SLOT alatt az ssh-nak egy subthread-je kell legyen. Tehát nézzük meg azt a subthread-et
(0)> th F100070F10023A00 |grep -w pvprocp |grep ">$"
DATA...........pvprocp :F100070F0004EC00 <F100070F0004EC00>
És ez alatt vajon milyen SLOT ID lapul?
(0)> proc F100070F0004EC00
             SLOT NAME     STATE      PID    PPID          ADSPACE  CL #THS
F100070F0004EC00  315*sshd     ACTIVE 013B06C 007403C 0000000041E95400   0 0001
315. BINGO.. Tehát akkor jó irányba haladtunk.. Akkor irány tova..

Tehát tudjuk, hogy a socketünk a F1000200032B7808 címen foglal helyet. Nézzük, hogy ez alá milyen pcb címet rendelt a rendszer:
(0)> sock F1000200032B7808 |grep -w pcb
    pcb.....@F1000200032B7A90  proto...@0000000004444880
Stimt.. Akkor még az is kell, hogy ez alatt a milyen PPCB cím van:
(0)>  tcb F1000200032B7A90 |grep ppcb
    ppcb........@F1000200032B7B98  route_6.....@F1000200032B7AE8
32B7B98.. Nem jött ez már szembe velünk valahol??? Ááá.. megvan.. az rmsock-nál! Dehogynem.. Tehát megvan a socket amit ténylegesen kerestünk.. Lehet tippelni milyen porton figyel :)
(0)> si F1000200032B7B98 tcpcb |grep lport
    oflowinfo... 00000000 lport....... 00000016 latype...... 00000000
(0)> hcal 16
Value hexa: 00000016          Value decimal: 22
16(hex) == 22(dec). Tehát a 22es porton.. Pontosan ez kellett nekünk!

Ha ezek után se hisszük, hogy jó socketre leltünk, akkor könnyű szerrel visszaellenőrizhetjük ezt is:
(0)> si F1000200032B7B98 tcpcb |grep socket
   laddr_6.....@F1000200032B7AC8  socket......@F1000200032B7808
F1000200032B7808.. Ez stimmel.. Tehát jól csináltunk mindent :))

Persze mondanom se kell, hogy ezt persze le lehet scriptelni, csak kérdés, hogy megéri e :) Az tény, hogy ha nincs a kezünk ügyében semmi használható eszköz, akkor használható ez is, de elég durva turkálást kell elkövetnünk, hogy ezt megtudjuk.. Arról nem is szólva, hogy ehhez eléggé mély szintre kell lemennünk, és a sok hülye számtól az ember szeme könnyen golyózni kezd :)