2011. július 12., kedd

NFS mount rejtelmek

Mai nap esett meg velem a következő: Mountolni akartam egy távoli NFS-en keresztül kiosztott FS-t, de Murphy épp nevetős kedvében volt és az alábbi üzenettel örvendeztetett meg:
client # mount server:/export /mnt
nfsmnthelp: 1831-019 9.149.40.8: System call error number -1.

mount: 1831-008 giving up on:
server:/export
System call error number -1.
Hát jó.. akkor induljunk neki a szokásos problem determinationnek:
- Az NFS mountolás során első körben az alábbi dolgok történnek (a teljesség igénye nélkül):
A kliens lekéri az NFS szerver IP címét (mivel ugye nem IP-vel akartunk csatlakozni) a géptől. Ennek pontos módja ugye a /etc/netsvc.conf-ban, illetve a /etc/resolv.conf-ban van tárolva.
Ha sikerül neki feloldani az IP címet, akkor megpróbál a távoli géppel egy standard RPC kommunikációt kiépíteni (port 111), majd az adott erőforráshoz (amit én hülye mountolni akarok) hozzáférni. Ezt persze vagy hagyja a szerver vagy sem. Ettől függetlenül azért ez nem egy lépéses játék -> csak az előbb felsorolt dolgokat 3 főbb pontra bontanám:
- IP feloldás
- RPC kommunikáció
- Resource hozzáférés (ide kapcsolnám az authentikációt is)

Persze ezek mellett még van jó pár dolog, de most így első körben azokkal nem törődök.. Nézzük át, hogy a fenti folyamatokhoz szükséges beállítások hogy is vannak:
- Nézzük meg, hogy a /etc/netsvc.conf hogy is próbálkozik a név feloldással:
client # grep -v ^# /etc/netsvc.conf
hosts = local,bind4
server # grep -v ^# /etc/netsvc.conf
hosts = local,bind4
Aham.. szóval ez jónak tűnik. Mind a szerver, mind a kliens a /etc/hosts-ot nézi első körben (local), majd megy a bind felé (IPv4en), ahogy az szerver esetén várható is.
Akkor nézzük tovább. van e bármiféle IP feloldás
client # host server
server is 192.168.1.10
server # host client
client is 10.1.0.20
A host szerint van (ne feledjük el, hogy a host parancs a /etc/netsvc.conf szabályain keresztül nézi ki az IP-t, ahogy azt általában az alkalmazások is teszik). Tekintve, hogy az alkalmazásoknak amúgy is a local felé kell fordulniuk 1x, így ezeket az IP-ket kénytelenek leszünk elfogadni (persze azért nem árt ellenőrizni, hogy a 2 IP valós e - ergo, hogy nincs e elszúrva a /etc/hosts-unk)

Akkor ezek után nézzük meg, hogy a standard hálózat él e mondjuk (sima ICMP, de a teszt erejéig jó lesz)
client # ping -c1 server
PING server (192.168.1.10) 56(84) bytes of data.
64 bytes from server (192.168.1.10): icmp_seq=1 ttl=243 time=75.6 ms

--- server ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 75.690/75.690/75.690/0.000 ms

server # ping -c1 client
PING client (10.1.0.20) 56(84) bytes of data.
64 bytes from client (10.1.0.20): icmp_seq=1 ttl=243 time=75.6 ms

--- client ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 75.690/75.690/75.690/0.000 ms
Az ICMP csomagok szépen átmennek, ergo a 2 gép eléri egymást.
# Note - jelen esetben a 2 gép 2 külön hálón van, viszont rálátnak egymás hálózataira, így ennek nem szabadna hibának lennie.

Persze lehet hogy van még tűzfal a 2 között, így nem árt ellenőrizni azt se, hogy a kliens rálát e a szerverre, és annak szolgáltatásaira:
client # showmount -e 192.168.1.10
Export list for 192.168.1.10:
/export (everyone)
client # rpcinfo -p 192.168.1.10
program vers proto port service
100000 4 udp 111 portmapper
100000 3 udp 111 portmapper
100000 2 udp 111 portmapper
100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100000 2 tcp 111 portmapper
100003 2 udp 2049 nfs
100003 3 udp 2049 nfs
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
200006 1 udp 2049
200006 4 udp 2049
200006 1 tcp 2049
200006 4 tcp 2049
100024 1 tcp 37470 status
100024 1 udp 50261 status
100133 1 tcp 37470
100133 1 udp 50261
200001 1 tcp 37470
200001 1 udp 50261
200001 2 tcp 37470
200001 2 udp 50261
100021 1 udp 50344 nlockmgr
100021 2 udp 50344 nlockmgr
100021 3 udp 50344 nlockmgr
100021 4 udp 50344 nlockmgr
100021 1 tcp 37472 nlockmgr
100021 2 tcp 37472 nlockmgr
100021 3 tcp 37472 nlockmgr
100021 4 tcp 37472 nlockmgr
100005 1 tcp 37711 mountd
100005 2 tcp 37711 mountd
100005 3 tcp 37711 mountd
100005 1 udp 50432 mountd
100005 2 udp 50432 mountd
100005 3 udp 50432 mountd
400005 1 udp 50433
Ez alapján én azt mondanám, hogy gyönyörűen látja a kliens amit kell. Ráadásul a showmount kimenetéből láthatjuk azt is, hogy az adott megosztás mindenki számára elérhetőnek kéne lennie.. Ezt azért ha lehet nem árt tényleg leellenőrizni is:
server # lsnfsexp
/export -rw
Ez alapján tényleg azt mondom, hogy ennek így jónak kéne lennie. (ha ezek közül valami nem megy, akkor nyomban gyanakodhatunk firewall/routing, vagy valami network típusú hibára )

2. lépésben szoktam nézni a rendszer (jelen esetben AIX) specifikus függőségeket.
Az egyik ilyen alap függőség, hogy az adott mappa (ahova mountolni akarunk) létezik e (tudom triviális, még is sokszor megszivatja az embert ,ha figyelmetlen):
server # ls -ld /mnt
drwxrwxrwx 229 root system 20480 07 Jun 13:05 /mnt
Persze általában ezt nem nézzük ennyire be, így a következő amire figyelni kell az az NFS beállítások mind a kliens, mind a szerver oldalon. Ezek közül is 2 van, ami az authentikációért felelhet (az NFS szabályokon felül) olyan módon, hogy kötötté teszik a standard portok használatát:
client # nfso -a |grep port
nfs_use_reserved_ports = 0
portcheck = 0
server # nfso -a |grep port
nfs_use_reserved_ports = 0
portcheck = 0
Általában illik a szerver és a kliens oldalnak ezen beállításokban egyezniük, mert ha nem az simán okozhat ilyesmi hibát. Sajna azonban itt nem ez a helyzet.
Ha ezek után se szokott menni, akkor szoktam azt a randa játékot játszani, hogy azt hiszem, hogy nem én, hanem az NFS szerver a hülye, így simán megpróbálom törölni, majd újra létrehozni az NFS megosztást ( tudom, Windows-os beütés, de néha működik)
server # smitty rmnfsexp
server # smitty mknfsexp
A probléma ott van, hogy nálam ezek után se működött a dolog, így végső kétségbeesésként megpróbálkoztam egy teljes NFS restartal :) - ki tudja, hátha beragadt valami:
server # stopsrc -g nfs
server # stopsrc -s portmap
server # rm -rf /etc/state /etc/rmtab /etc/xtab
server # startsrc -s portmap
server # startsrc -g nfs
server # exportfs -a
A gáz onnan indult, hogy még ezek után se ment a játék.. Más kliensek gond nélkül fel tudták csatolni a megosztást, de ez az 1 makacsul nem engedett.
Ekkor döntöttem el, hogy akkor nézzük meg mélyebbről is a játékost - tracelgessünk kicsit:
client # startsrc -s iptrace -a "-a -b /tmp/iptrace.bin"
client # mount 192.168.1.10:/export /mnt
client # stopsrc -s iptrace
client # ipreport -rnvs /tmp/iptrace.bin > /tmp/iptrace.bin.out
A problémám ott kezdődött, amikor konstatálnom kellett, hogy az egyetlen gyengécske nyom kb ennyiben nyilvánult meg:
Packet Number 260
ETH: ====( 86 bytes received on interface en0 )==== 13:12:00.036155006
ETH: [ 00:0f:90:aa:ea:ff -> 00:02:55:33:ec:e5 ] type 800 (IP)
IP: < SRC = 192.168.1.10 > (server)
IP: < DST = 10.1.0.20 > (client)
IP: ip_v=4, ip_hl=20, ip_tos=0, ip_len=72, ip_id=17465, ip_off=0
IP: ip_ttl=57, ip_sum=f220, ip_p = 6 (TCP)
TCP:
TCP: th_seq=3365614187, th_ack=44423836
TCP: th_off=5, flags
TCP: th_win=65535, th_sum=5ee7, th_urp=0
RPC: Record Marker: Size = 28, Last Fragment (0x8000001c)
RPC: **REPLY** XID=1310050721
RPC: 100005(MOUNTPROG) 1(MOUNTPROC3_MNT)
RPC: Reply Stat: MSG_ACCEPTED
RPC: Accepted Reply Stat: SUCCESS
MNT: Status=Protocol Error, Bad mnt_stats (-1)
Fejvakarás, töprengés... Wattafák... Vissza az alapokhoz..
Az stimt, hogy a kapcsolat kialakításához kell egy IP kapcsolat (ami megy is az előző lekérések alapján), viszont belegondolva van az NFS-nek egy olyan funkciója, hogy "reverse name lookup". Ez a funkció elvileg arra hivatott, hogy garantálja, hogy a kliens a szerverrel, illetve a szerver a kliensel beszél az által, hogy a kapcsolat felépítésekkor leelenőrzi azt, hogy a kiépülendő kapcsoalat valóban a 2 fél között jönne e létre.
Ezt valahogy úgy próbálja megcsinálni, hogy:
- A kliens valahogy feloldja a szerver IP címét, majd erre megpróbál csatalakozni
- A kapcsolat során elküldi azt, hogy ő kicsoda, illetve mi is az IP címe
- A szerver reigsztrálja a kérést, majd megnézi, hogy a kliens az ő névfeloldása alapján valóban az e, akinek állítja magát (ergo csinál vissza fele is egy névfeloldást)
- Amennyiben a feloldott IP egyezik azzal, ahonnét jött a kapcsolat akkor megy tovább a kapcsolat kiépítésével
- Természetesen a kliens is eljátsza ugyan ezt (hiszen RPC kommunikációról beszélünk), és ha már ott jár, akkor a szervertől kapott azonosítóval megnézni, hogy valóban jó géppel akar e autholni

Ez security oldalról tényleg értelmes dolog.. Hiába van egy világnak megosztott NFS megosztásom, attól még nem akarom, hogy ezt valaki kihasználva bármi csúnyaságot csináljon. Szerver esetében ugye átalában a netsvc.conf alatt a local az elsődleges rule, így ez miatt erősen ajánlott, hogy mind a kliens, mind a szerver tudjon a másik pontos címéről a /etc/hosts alatt.

A probléma az, hogy ugye ezt ellenőriztük fentebb.. Őőő.. vagyis nem teljesen.. Mint mondtam a vissza azonosítás oda vissza irányul -> Kell az is, hogy a gép önmagáról is "hiteles" adatot küldjön.. És itt volt a kutya elásva: A szerver oldalon a 'server' más IP címmel volt felvéve a /etc/hosts alatt (az ok egyszerű: A 'server' alapból egy másik alhálózatért felel, és azokat a kapcsolatokat meg csak ezen keresztül érheti el).

Ez miatt viszont az egész reverse name lookup meghiusul, mi meg nézhetjük a földön gyülekező hajtömegetet és a ráncokat a tükörbe..
A megoldás ezek után adná magát: Írjuk át a szervernél a /etc/hosts-ban a 'server' IP címét.. A probléma az, hogy ebben a környezetben, ahol a szerver másik alhálóért is felel (vagy inkább azt tekinti elsődlegesnek) ezt nem teheti meg az ember, mert a végén másik kliensel szúr ki.

Akkor viszont marad a másik útvonal: Ki kéne kapcsolni ezt a biztonsági funkciót.. A kérdés csak, hogy hogyan.

Nos.. a vicc a következő: A mountolás ezen fázisában ezért a funkcióért az rpc.mountd felel a szerver oldalon.. Ennek meg a vicc kedvéért van egy nem nagyon dokumentált kapcsolója, amit az ODM alá felvéve gyönyörűen lehet semlegesíteni ezt a működést. Az átállítás módja kb így néz ki:
server # stopsrc -s rpc.mountd
server # chssys -s rpc.mountd -a "-x"
server # startsrc -s rpc.mountd

Ez után, akkor próbálkozunk újra:
client # mount server:/export /mnt
client # mount |grep mnt
server /export /mnt nfs3 12 Jul 08:59
Öröm és bóduttá...

3 megjegyzés:

  1. A kliens is AIX volt? Mert ez a showmount parancs nagyon nem remlik....

    VálaszTörlés
  2. Mind a szerver, mind a kliens AIX volt..
    Showmountról meg bővebben itt:
    http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.cmds/doc/aixcmds5/showmount.htm

    VálaszTörlés
  3. NFS restart eseten en az inditast egyszerubben intezem el:

    /etc/rc.nfs

    Inittabbol is ez fut le, ellenben nem indit el mindenfele felesleges daemont (nfsrgyd gssd) ;)

    VálaszTörlés