mercoledì 17 febbraio 2016

Cosa significa essere "della vecchia scuola"

Un giovane app developer sveglio e brillante ed un burbero panciuto cinquantenne programmatore old-school stanno bevendo qualche drink al bar. Dopo qualche bicchierino di troppo, decidono di avviare un Potente Progetto sulla Sicurezza di Internet: scandire ogni mese tutti gli indirizzi IPv4 e tener nota degli host che rispondono al ping e che hanno aperta qualche porta FTP o Telnet, espandendo magari in futuro il software per supportare qualche altra porta.

Vediamo le differenze tra il giovane e pimpante skilled App Developer e il vecchio trippone programmatore rispetto a quattro punti importanti:
  1. come si fa;
  2. quale metodo è il più veloce
  3. quale è il più estensibile (aggiungere altre porte);
  4. quale è il più costoso in termini di potenza di calcolo, memoria, disco.


1. Scelta del linguaggio di programmazione.

AppDeveloper: bisogna usare Python, facile da imparare, performante, facile da manutenere.

Trippone: per queste cose si lavora in C, veloce, performante, grosso modo facile da manutenere.


2. Scelta delle strutture dati.

AppDeveloper: eh, qui bisogna usare JSON (che oggi si usa dappertutto, è facile da leggere, e tutti lo sanno usare): ogni host sarà descritto da qualcosa del tipo:
{
 "ip": "123.45.67.89",
 "state": "up",
 "ports": {
  "20": "open",
  "21": "open",
  "23": "closed",
 }
}

Gli indirizzi IPv4 sono 2³², cioè circa 4,2 miliardi, di cui stimeremmo circa 300 milioni attivi. Sono sufficienti perciò 50-60 gigabyte di spazio su disco. Aggiungere altre porte è banale: basta qualche riga in più nel pacchetto JSON.

Trippone: lo stato è solo up/down (1 bit), le tre porte sono solo open/closed (1 bit ciascuna), per cui bastano quattro files che contengano un array di bit (4,2 miliardi di bit = 512Mb ciascuno = due gigabyte totali di spazio su disco). Aggiungere altre porte è banale: basta qualche file in più di 512 Mb.


3. Statistica mensile sugli host attivi e sulle porte open

AppDeveloper: ooh, qui facciamo Big Data! Posso scandire l'archivio con la tecnologia Hadoop, oppure indicizzare i documenti JSON aggiungendo un file indice di una decina di gigabyte. Per esempio conosco qualche libreria che...

Trippone: mi basta contare i bit uguali a 1 nel rispettivo file di 512Mb; può bastare una banalissima lookup-table del tipo: "quando vedi un byte 11010011 allora aggiungi 5 al conteggio". Praticamente è O(n) con una costante piccolissima.


4. Verifica di un singolo indirizzo IP

AppDeveloper: ehi, smart! qui mi basta fare una ricerca binaria nel file indice di una decina di gigabyte, ed estrarre il pezzetto JSON che ci interessa. Se la ricerca non trova nulla, allora l'host è down e non ha porte open.

Trippone: l'archivio indirizzi è sequenziale (512 Mb) per cui in O(1) si trova la posizione del bit in ognuno dei file e dal valore 0/1 si capisce up/down o open/closed.


5. Verifica di un gruppo di indirizzi IP (per esempio una subnet/24)

AppDeveloper: cool story, bro! mi basta scandire il file indice e fare pattern-matching con le regular expressions. Oppure fare 256 ricerche binarie sugli indirizzi di tutta la subnet (poiché infatti una subnet/24 corrisponde a 256 indirizzi).

Trippone: avendo mappato gli indirizzi IP consecutivamente, una subnet/24 consisterà di 256 bit consecutivi: basta calcolare l'indirizzo del primo e leggere i 256 bit (cioè 32 bytes) a partire da lì dal file corrispondente di 512 Mb. Praticamente O(1).


6. Conteggio del numero di host che hanno una determinata combinazione di porte open

AppDeveloper: oh, yeah, American Dream! questo è un lavoro Bìggh Dèta per la tecnologia Hadoop, bisogna scrivere un map/reduce, oppure si può fare aggiungendo un nuovo indice.

Trippone: è di nuovo un conteggio? basta scandire i quattro file 512 Mb confrontando i singoli bit con la combinazione richiesta. Complessità lineare: O(n) sul numero dei files.


7. Conteggio di quanti host sono stati attivi durante gli ultimi tre mesi

AppDeveloper: don't break my heart, babe! per ogni mese creiamo un'apposita directory con il database e gli indici; quindi estraiamo da ogni database una lista di host attivi, e quindi joiniamo e deduplichiamo le ultime tre liste.

Trippone: creeremo un'apposita directory per ogni mese; basterà fare un'operazione "OR" bit a bit del file binario host delle ultime tre directory, conteggiando i bit risultanti a 1. Complessità O(n) con costante molto piccola.


8. Conteggio di quanti host sono stati aggiornati questo mese (cioe da up a down o viceversa)

AppDeveloper: I'm a Belieber, Justin! è facile, anche se costosetto: basterà scandire l'archivio di questo mese, estrarre il JSON di ognuno dei circa 300 milioni di host rispetto al mese precedente e verificare up/down e down/up.

Trippone: basterà fare un'operazione "XOR" bit a bit del file binario host degli ultimi due mesi, conteggiando i bit risultanti a 1. Solita O(n) con costante molto piccola.


9. Conteggio di quanti host sono stati attivi in almeno x degli ultimi 12 mesi.

AppDeveloper: funny compilation, dude! l'operazione è lunghetta perché bisogna creare un nuovo database in cui inserire i campi "indirizzo" e "mesi attivi", e poi scandire uno per uno i dodici database precedenti per aggiornare i conteggi, ed infine conteggiare quelli in cui il campo "mesi attivi" è maggiore o uguale a x.

Trippone: creo in RAM un array di 4 miliardi di interi da 4 bit ciascuno (dunque mi occupa 2Gb RAM), leggo uno per uno gli ultimi 12 mesi aggiornando i contatori corrispondenti. Alla fine conto quanti sono maggiori o uguali a x. Se invece la RAM scarseggia, allora posso suddividere l'operazione in "fette" da 16Mb-256Mb e sommare infine i conteggi parziali. Alla fine della fiera, in entrambi i casi, la complessità è O(n) con costante molto piccola.


Indovinate perché il giovane e sveglio app developer se n'è andato via stizzito e imbufalito.

2 commenti: