$ cat /dev/random
ripley's miscellanous debris

Net::Telnet ti da una mano

(2006/05/27)

Ruby e’ un ottimo linguaggio ad oggetti e come molti sapranno sta letteralmente spopolando nell’ambito delle web-application, mettendo in serie difficolta’ php (che paga ora la sua scarsa innovativita’, preferendo preservare lo status quo), java (e questo pochi se lo aspettavano) e python (che invece in ambito web e’ entrato di fresco), ma pochi ancora lo utilizzano in ambito di scripting di sistema.

Durante l’amministrazione di sistema si presentano spesso delle situazioni che richiedono l’esecuzione di azioni ad elevata meccanicita’.

Queste azioni meccaniche oltre ad essere molto noiose (scazzac…zi e’ il termine tecnico utilizzato da noi del settore :-)) e fonte di enormi perdite di tempo, sono soprattutto molto error prone.

La mente umana si sa e’ dotata di una innata fantasia ma e’ molto scarsa in tutti i lavori ripetitivi:

10 ripeti un milione di volte la stessa cosa 
20 per fare prima o poi qualche immane c..zata 
30 di cui ti pentirai nelle seguenti 12 ore... 
30 goto 10

Quindi abbiamo sufficienti scuse per cercare di scappottarci (termine tecnico che sta per riassegnare le risorse) anche questa ingrata mansione e sbolognarla alla nostra protesi al cervello (il termine tecnico usato per indicare il pc).

Divagazione Storica

Inizialmente gli amministratori di sistema automatizzavano tutto utilizzando le tante micro-utility di unix e lo shell scripting come collante.

Ma man mano che i compiti si fanno complessi (e quindi lo script piu’ lungo e articolato) gli script shell cominciano a diventare piuttosto difficili da comprendere e debuggare e si comincia il freeclimbing sugli specchi…

E cosi’ nasce perl… con il quale anche gli script piu’ piccoli risultano piuttosto difficili da comprendere e debbuggare :-PPPPP

A parte gli scherzi perl ha rappresentato un grosso passo avanti per quanto riguarda la complessita’ dei compiti che gli script di sistema sono in grado di compiere, con la sua straordinaria capacita’ di sintesi, ma questo purtroppo a discapito della leggibilita’ :-( ... ora il compito preferito da noi amministratori e’ capire cosa ca..o fanno questi script in perl che nemmeno Larry Wall riuscirebbe a leggere :-)))

Ruby da parte sua:

A mio avviso e’ un ottimo candidato per segnare una vera svolta per quanto riguarda la qualita’ del codice di questi script di sistema, e’ tutto potenziale che aspetta solo la carica per poter esplodere.

In ambito web la carica e’ stata Ruby On Rails, in questo ambito chissa’ :-)

Nel mentre siamo qui ad aspettare questa carica possiamo saggiarne un piccolo esempio concreto.

Scenario

Ho un piccolo router adsl (un USR 9105) che, anche se non evidenziato da nessuna parte sulla scatola, e’ equipaggiato con un kernel linux e un piccolo sistema composto da busybox, iptables, route etc. etc.

Il router puo’ essere configurato attraverso una comoda (quanto limitata) interfaccia web e attraverso un’interfaccia telnet.

Attraverso l’interfaccia telnet abbiamo a disposizione una shell busybox ristretta (non c’e’ ls ad esempio… ma c’e’ cat :-P) e un po’ di comandi tra cui oltre a quelli specifici dell’usr9105 abbiamo piu’ o meno ufficiosamente iptables :-)

Problema

L’interfaccia telnet e’ stata una manna perche’ mi permette di bypassare alcune limitazioni dell’interfaccia web (e non del router in se) come ad esempio la possibilita’ di NATting di una sola classe di indirizzi:

cioe' se uso 2 classi di indirizzi (ad esempio 192.168.0.x e 10.0.x.x) 
posso assegnare due ip al router (uno per classe) ma una sola potra' 
essere NATtata (quella dell'indirizzo primario)

CHE PALLE!!!

Per fortuna abbiamo l’interfaccia telnet e iptables!!!

Ci logghiamo via telnet, facciamo un bel:

iptables -t nat -A POSTROUTING --src 10.0.0.0/16 -j MASQUERADE

e abbiamo risolto.

Si… ma fino a quando non si riavvia il router!!!

CHE PALLEEEEE!!!

Non ci vuole molto a rendersi conto che in questo modo non stiamo facendo altro che caricarci un compito ingrato e ripetitivo (alla Lino Banfi operaio in fabbrica) che si presentera’ quando meno lo vorremo.

Soluzione

Armati di Ruby e Net::Telnet possiamo risolvere in 4 e 4 = 8 (righe di codice ;-)):

require 'net/telnet'

def test_172nat(usr9105)
  nat_table_buf = ""
  test_172nat_rx = /\n(MASQUERADE).*(10.0.0.0)/

  usr9105.cmd("iptables -t nat -L") { |c| nat_table_buf << c }

  if result = test_172nat_rx.match(nat_table_buf) then
    puts "OK: #{$1} #{$2}"
    return true
  else
    puts "KO"
    return false
  end
end

usr9105 = Net::Telnet::new("Host" => "10.0.0.1",
                               "Timeout" => 10,
                               "Prompt" => /[$%#>] \z/n)
usr9105.login("admin", "yourpassword") { |c| print c }

if not test_172nat(usr9105) then
   usr9105.cmd("iptables -t nat -A POSTROUTING --src 10.0.0.0/16 -j MASQUERADE")
   test_172nat(usr9105)
end

usr9105.close

Ovviamente questo e’ solo un piccolo snippet (imperfetto e senza un error handling serio), ma credo che renda l’idea.

Lo script e’ pienamente leggibile ma allo stesso tempo molto compatto, senza considerare il fatto che all’aumentare della complessita’ ci verranno in aiuto le caratteristiche di orientamento agli oggetti e meta-programmazione proprie di ruby (che sono inesistenti o primitive in perl)

Conclusione

Se siete amministratori di sistema imparate ruby e abbandonate perl al piu’ presto prima di bruciare nelle fiamme dell’inferno… ricordate

Dovete trovare ruby...
 prima che sia lui a trovare voi...

e se conoscete altri amministratori di sistema che scrivono script in perl raccontate anche a loro la parabola della povera Mildred :-)


Full of CC licensed ripley's debris
HTML and CSS Design by Nicolas Fafchamps
Generated with Rote and Rog