PF e la normalizzazione del traffico di rete ============================================ Gianluigi Spagnuolo, Kirash Indice ------ Introduzione Parte I Introduzione Cosa deve fare Cosa non deve fare Come funziona Parte II Real World: la direttiva Scrub del Packet Filter di OpenBSD Introduzione Normalizzazione IP Normalizzazione IPv6 Normalizzazione TCP Ascolto e dimentico, vedo e ricordo, faccio e capisco Parte III Real World: unclean, il sanity check di IPTables Introduzione Conclusioni Riferimenti Introduzione ============ Questo documento tratta della normalizzazione del traffico di rete. La prima parte affronta l'argomento dal punto di vista teorico. La seconda parte presenta alcuni stralci di codice, ampiamente commentati, dell'implementazione della direttiva "scrub" all'interno del Packet Filter di OpenBSD. La terza parte illustra brevemente il sanity check eseguito dall'estensione unclean di IPTables, il firewall dei sistemi GNU/Linux. Un normalizzatore (normalizer) altro non è che un dispositivo che si pone nei punti di ingresso della rete con l'unico scopo di rimuovere le eventuali ambiguità presenti nel flusso di pacchetti che lo attraversa. PARTE I Cosa deve fare -------------- Lo scopo del normalizzatore è quello di convertire i pacchetti che presentano delle "ambiguità", e che potrebbero essere interpretati in modo differente dai vari destinatari finali, in un flusso "normalizzato" e omogeneo, univocamente interpretato da tutti gli end-point. A prima vista un meccanismo del genere potrebbe sembrare quantomeno superfluo, invece risulta essere di grande utilità soprattutto se affiancato ad un Network Intrusion Detection System o ad un firewall. I NIDS basano la loro efficacia sul concetto che osservando i pacchetti in transito su una interfaccia sia possibile predirne il comportamento, e bloccarli se risultano dannosi per il destinatario finale. Tutto questo non ha più senso quando il NIDS incontra pacchetti creati ad-hoc da un eventuale attaccante e viene aggirato (attacchi di inserzione ed evasione dei pacchetti [1]). In realtà, differenze nell'interpretazione del flusso di dati, si verificano anche quando un NIDS ha a che fare con traffico "regolare", questo accade perché, in genere, un network IDS si trova su una macchina diversa da quella dell'end-point e osserva un punto completamente diverso della rete; queste discrepanze sono il frutto di diverse implementazioni dei driver di rete e differenze fisiche tra le macchine. In Tabella 1 c'è un esempio di quanto appena detto, è rappresentato il comportamento dei vari sistemi operativi in presenza di overlap dei frammenti IP. +-------------------+--------------------------------------------+ | Sistema Operativo | Comportamento | +-------------------+--------------------------------------------+ | Windows NT | Prende sempre in considerazione i dati che | | | arrivano per primi | +-------------------+--------------------------------------------+ | 4.4BSD | Prende sempre in considerazione i nuovi | | | frammenti in caso di forward overlap | +-------------------+--------------------------------------------+ | Linux | Prende sempre in considerazione i nuovi | | | frammenti in caso di forward overlap | +-------------------+--------------------------------------------+ | Solaris | Prende sempre in considerazione i dati che | | | arrivano per primi | +-------------------+--------------------------------------------+ | HP-UX | Prende sempre in considerazione i nuovi | | | frammenti in caso di forward overlap | +-------------------+--------------------------------------------+ | Irix | Prende sempre in considerazione i nuovi | | | frammenti in caso di forward overlap | +-------------------+--------------------------------------------+ Tabella 1 Ebbene il normalizer rimuove le ambiguità (volute o casuali) presenti nel flusso in ingresso, passando al NIDS un flusso normalizzato in modo da metterlo in condizioni di prevedere correttamente il comportamento del destinatario finale. A grandi linee lo stesso ragionamento vale per i firewall. Sebbene lo scopo principale del normalizer sia quello di normalizzare i pacchetti, spesso il traffico non può essere corretto in accordo con le specifiche del protocollo. In questi casi l'azione da intraprendere dipende dalla configurazione del normalizzatore, non c'è bisogno di aggiungere che una politica di sicurezza seria prevede in questi casi il rifiuto di tutti i pacchetti illegali e non "normalizzabili". Oltre a correggere le incongruenze, il normalizer interviene anche su alcuni pacchetti che, benché siano perfettamente legali dal punto di vista delle specifiche del protocollo, potrebbero creare problemi agli end-point. Ad esempio interviene sul campo TTL (Time-To-Live) dei pacchetti IP, in modo da evitare che i pacchetti con un valore basso di TTL, visti dal NIDS, non arrivino al destinatario finale. Oltre ad intervenire sul traffico in ingresso, un normalizzatore opera anche sui pacchetti in uscita. Ad esempio va a sovrascrivere il valore del campo "identification" dei pacchetti IP con un valore casuale, evitando in questo modo i port scan di tipo stealth e rendendo più complicato il lavoro dei vari tool per il fingerprinting. Cosa non deve fare ------------------ Un normalizzatore deve solo normalizzare il traffico e nient'altro, non si deve occupare né di filtrare i pacchetti né di individuare possibili attacchi, a questo ci pensano rispettivamente i firewall e i network intrusion detection system. Perché quando si implementa un dispositivo di normalizzazione bisogna prestare particolare attenzione alle performance, il rischio, non tanto remoto, è quello di congestionare la rete. Un normalizzatore deve garantire un buon attraversamento dei pacchetti irregolari, che devono essere normalizzati e quindi riscritti, e inoltre non deve avere un impatto negativo sul traffico regolare. L'incidenza sulle prestazioni generali della rete non è facilmente quantificabile, troppe sono le parti in gioco; bisogna tener conto del protocollo che si va a normalizzare, del tipo di rete, del numero di pacchetti, della complessità delle regole di scrubbing, dell'efficienza della scheda di rete e di tutto l'hardware in generale, etc. Come funziona ------------- In genere un normalizzatore opera prevalentemente, ma non solo, sugli header dei pacchetti da esaminare. Ogni campo dell'intestazione viene confrontato con un range di valori ammessi, e ne viene controllato il contenuto alla ricerca di ambiguità e di valori che potrebbero avere degli effetti indesiderati sull' end-point. Ad esempio, nel caso di normalizzazione IP, in genere, si controlla se la lunghezza dell'header è troppo lunga o troppo corta, se la lunghezza totale è corretta, controlla se gli indirizzi di partenza e di destinazione sono validi, esamina il campo TTL e le opzioni, verifica la correttezza del checksum e così via. Nel caso di normalizzazione TCP, oltre alle verifiche riguardanti la lunghezza di header e la validità del checksum, vengono eseguiti controlli sulla correttezza dei flag e sul numero di sequenza. Per gli altri protocolli, a grandi linee, valgono le stesse considerazioni. Di seguito vedremo in dettaglio un esempio di implementazione di un normalizzatore, e più precisamente poseremo l'attenzione sulla direttiva scrub del Packet Filter di OpenBSD, senza dimenticare Linux e IPTables. PARTE II Real World: la direttiva Scrub del Packet Filter di OpenBSD =========================================================== La direttiva scrub di PF si occupa della normalizzazione e della deframmentazione del traffico TCP/IP. In questo documento ci occuperemo solo del primo aspetto. La sintassi della direttiva scrub è molto simile alla sintassi per il filtraggio, questo rende facile usare scrub selettivamente solo su alcuni pacchetti. Un semplice esempio dell'uso di scrub all'interno delle regole di pf è il seguente: scrub in all questa riga applicherà la direttiva scrub a tutti i pacchetti in ingresso su tutte le interfacce. Oltre all'uso barbaro visto poc'anzi, è possibile usare nelle regole di scrubbing le seguenti opzioni riguardanti la normalizzazione: no-df azzera il bit "don't fragment" nell'intestazione dei pacchetti IP, vedremo in seguito l'utilizzo di questa opzione; random-id sostituisce il campo "identification" dei pacchetti IP in uscita con un valore casuale per compensare i valori predicibili usati da alcuni sistemi operativi; min-ttl num impone un valore minimo (num) del "Time To Live" (TTL) nell'intestazione dei pacchetti IP; max-mss num impone un valore massimo (num) del "Maximum Segment Size" (MSS) nell'intestazione dei pacchetti TCP. Le opzioni che gestiscono i frammenti sono invece "fragment reassemble", "fragment crop" e "fragment drop-ovl" che si occupano della gestione dei frammenti e del trattamento dei frammenti duplicati o che si vanno a sovrapporre a quelli già ricevuti. Un esempio un po' più rappresentativo di una regola di scrubbing è il seguente: scrub in on rl0 all fragment reassemble min-ttl 20 max-mss 1400 Per maggiori dettagli sulla sintassi della direttiva scrub rimando alle FAQ ufficiali di OpenBSD [3]. Senza entrare nei dettagli della deframmentazione vediamo di seguito come è implementata la normalizzazione all'interno di PF. Nota: il codice utilizzato nella stesura di questo articolo fa riferimento alla versione 3.3 dei sorgenti di OpenBSD [2]. Normalizzazione IP ------------------ La funzione che si occupa di normalizzare il traffico IP [7] all'interno di PF è pf_normalize_ip in /usr/src/sys/net/pf_norm.c [2], ecco di seguito il prototipo: int pf_normalize_ip(struct mbuf **, int, struct ifnet *, u_short *); Le variabili che incontreremo negli stralci di codice hanno il seguente significato: "h" è l'header del pacchetto da normalizzare, e "r" è una struttura di tipo "pf_rule" definita in pfvar.h, che in sostanza rappresenta il contenuto di una regola di PF, in questo caso è una regola per lo scrubbing. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figura 1: Header IP Il pacchetto viene scartato se la lunghezza della sua intestazione (hlen) è minore di 20 byte, ovvero se l'header, raffigurato in figura 1 è incompleto: if (hlen < (int)sizeof(struct ip)) goto drop; e viene scartato anche se hlen è maggiore della lunghezza totale del pacchetto: if (hlen > ntohs(h->ip_len)) goto drop; Se il flag "Don't fragment" è settato e il fragment offset è diverso da zero il pacchetto viene scartato in quanto malformato: if (h->ip_off & htons(IP_DF)) { goto bad; } Alcuni sistemi operativi, però, generano pacchetti frammentati con il bit "don't fragment" settato, questo succede ad esempio con NFS. Come visto in precedenza, scrub rifiuterà tali pacchetti a meno che non sia specificata l'opzione "no-df". Usando l'opzione "no-df" invece viene azzerato il bit "don't fragment" nell'intestazione dei pacchetti IP. Se viene usata l'opzione min-ttl di scrub, che impone un valore minimo del Time To Live (TTL) nell'intestazione dei pacchetti IP, il TTL di ogni pacchetto (h->ip_ttl) viene forzato al valore passato a scrub. Ad esempio con la regola scrub in on rl0 all min-ttl 20 si impone il valore 20 come TTL per tutti quei pacchetti che hanno un valore inferiore. Questa è una opzione da usare con cautela in quanto c'è la possibilità di creare loop infiniti, oltre a creare problemi a traceroute e simili. if (r->min_ttl && h->ip_ttl < r->min_ttl) h->ip_ttl = r->min_ttl; Se è impostata l'opzione "random-id" all'interno della regola di scrubbing il valore del campo "identification" dei pacchetti IP in uscita viene sostituito con un valore casuale, generato dalla funzione ip_randomid, per compensare i valori predicibili usati da alcuni sistemi operativi. if (r->rule_flag & PFRULE_RANDOMID) h->ip_id = ip_randomid(); Normalizzazione IPv6 -------------------- La funzione che si occupa di normalizzare il traffico IPv6 è pf_normalize_ip6 in /usr/src/sys/net/pf_norm.c [2], di seguito il prototipo: int pf_normalize_ip6(struct mbuf **, int, struct ifnet *, u_short *) Anche nel caso di pacchetti IPv6 [7], figura 2, è possibile gestire il Time To Live attraverso l'opzione min-ttl di scrub. Il valore passato come argomento a min-ttl va a modificare il campo "Hop limit" (ip6_hlim). if (r->min_ttl && h->ip6_hlim < r->min_ttl) h->ip6_hlim = r->min_ttl; Anche in questo caso, come per i pacchetti IP, l'opzione min-ttl è da usare con estrema cautela. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| Traffic Class | Flow Label | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Payload Length | Next Header | Hop Limit | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Source Address + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Destination Address + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figura 2: Header IPv6 Oltre ai soliti controlli sulle dimensioni delle intestazioni dei pacchetti e delle estensioni, particolare attenzione viene rivolta ai jumbogram. Senza entrare troppo nei dettagli, non è questa la sede adatta, un jumbogram è un pacchetto IPv6 contenente un payload di dimensione superiore ai 65.535 byte. Tali pacchetti sono segnalati dalla presenza dell'opzione "Jumbo Payload" di tipo "hop-by-hop". L'header di un pacchetto IPv6 ha un campo "Payload Length" di 16 bit, mentre l'opzione "Jumbo Payload", figura 3, mette a disposizione il campo "Jumbo Payload Length" di 32-bit e permette quindi di gestire i cosidetti jumbogram. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Opt Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Jumbo Payload Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figura 3: Jumbo Payload In sintonia con le specifiche del protocollo (RFC2675) [7], il campo "Payload Length" (ip6_plen) dell'intestazione IPv6 deve essere posto a zero in ogni pacchetto che presenta l'opzione "Jumbo Payload", in caso contrario il pacchetto viene scartato. if (h->ip6_plen != 0) goto drop; Se è presente l'opzione "Jumbo Payload" e la lunghezza (jumbolen) del pacchetto IPv6 (senza l'intestazione), è minore di IPV6_MAXPACKET, che vale 65535, il pacchetto viene scartato. if (jumbolen <= IPV6_MAXPACKET) goto drop; Il pacchetto viene scartato anche se il campo "Payload Length" del pacchetto IPv6 è posto a zero e non è presente l'opzione Jumbo Payload. if (ntohs(h->ip6_plen) == 0) plen = jumbolen; else plen = ntohs(h->ip6_plen); if (plen == 0) goto drop; Come detto in precedenza "jumbolen" è la lunghezza del pacchetto IPv6 con "Jumbo Paylod", e vale zero se non è presente tale opzione. In conclusione il pacchetto IPv6 viene rifiutato anche se oltre all'opzione "Jumbo Payload" è presente l'estensione "Fragment". Normalizzazione TCP ------------------- La funzione che si occupa di normalizzare i pacchetti TCP [7], figura 4, è pf_normalize_tcp in /usr/src/sys/net/pf_norm.c [2], di seguito il prototipo: int pf_normalize_tcp(int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *); Per i nomi delle variabili abbiamo che "th" è una struttura di tipo "tcphdr", e "flags" corrisponde a "th->th_flags". +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | data | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figura 4: Header TCP Se sono settati i flag SYN e RST il pacchetto è illegale e viene scartato, se invece oltre a SYN è settato il flag FIN, quest'ultimo viene posto a zero e il pacchetto prosegue per la sua strada. Il pacchetto viene scartato anche se si ha allo stesso tempo SYN=0, ACK=0 e RST=0. if (flags & TH_SYN) { if (flags & TH_RST) goto tcp_drop; if (flags & TH_FIN) flags &= ~TH_FIN; } else { if (!(flags & (TH_ACK|TH_RST))) goto tcp_drop; } Poiché i flag FIN, PUSH e URG sono validi solo se anche ACK è settato, in tutti gli altri casi il pacchetto viene rifiutato, ad esempio se FIN=1 e ACK=0. if (!(flags & TH_ACK)) { if ((flags & TH_FIN) || (flags & TH_PUSH) || (flags & TH_URG)) goto tcp_drop; } Se il flag URG non è settato viene rimosso l'urgent pointer. if (!(flags & TH_URG) && th->th_urp) { th->th_urp = 0; } Il pacchetto viene scartato anche se la lunghezza dell'header TCP non è corretta. if (th->th_off < (sizeof(struct tcphdr) >> 2)) goto tcp_drop; Ascolto e dimentico, vedo e ricordo, faccio e capisco ----------------------------------------------------- Ed ora, dopo tante parole e tanto codice, andiamo a vedere come si comporta il nostro dispositivo sul campo. Per farlo creeremo dei pacchetti ad hoc e li invieremo al nostro end-point facendoli passare attraverso una macchina che fungerà da firewall. Per creare i pacchetti "ambigui" useremo Nemesis [8]. Sul firewall, realizzato ovviamente con OpenBSD e PF, sono caricate solo le regole di scrubbing, in particolare per i pacchetti in ingresso abbiamo impostato un valore minimo di TTL pari a 20: # pfctl -s rules @0 scrub in all min-ttl 20 fragment reassemble @1 scrub out all fragment reassemble Di seguito vedremo tre esempi di normalizzazione: 1) Pacchetto con i flag SYN e FIN settati. Come abbiamo visto in precedenza tale pacchetto non viene scartato, ma scrub interviene ponendo a zero il flag FIN. Creiamo il pacchetto con nemesis-tcp # nemesis-tcp -fS -fF -S 192.168.1.1 -D 192.168.2.1 e vediamo cosa arriva all'end-point: # tcpdump -n -t -vv -i rl0 tcpdump: listening on rl0 192.168.1.1.42069 > 192.168.2.1.23: S [tcp sum ok] 420:420(0) win 512 (DF) [tos 0x18] (ttl 254, id 11367) come si vede dall'output di TcpDump [8], il pacchetto arriva con il solo flag SYN settato. 2) Time To Live inferiore al valore di min-ttl. Quando al firewall arriva un pacchetto con un TTL inferiore al valore passato come argomento a min-ttl nella regola di scrubbing, nel nostro caso 20, il firewall riscrive il pacchetto con un nuovo valore per TTL. Creiamo un pacchetto con un Time To Live pari a 12 # nemesis-tcp -fS -S 192.168.1.1 -D 192.168.2.1 -T 12 e vediamo che al destinatario finale arriva un pacchetto con un valore di TTL pari a 20 # tcpdump -n -t -vv -i rl0 tcpdump: listening on rl0 192.168.1.1.42069 > 192.168.2.1.23: S [tcp sum ok] 420:420(0) win 512 (DF) [tos 0x18] (ttl 20, id 61302) 3) Pacchetto con il solo flag FIN settato. Per concludere "iniettiamo" nella rete un pacchetto non valido, avente il solo flag FIN settato. Creiamo il nostro pacchetto con il solito Nemesis: # nemesis-tcp -fF -S 192.168.1.1 -D 192.168.2.1 e vediamo cosa accade. Stavolta TcpDump, posto in ascolto sull'end-point, non ci è d'aiuto poiché il pacchetto ha terminato la sua corsa sul firewall. E' stato scartato perché non corretto, il flag FIN è ritenuto valido solo se anche il flag ACK è settato. Ovviamente non si esauriscono qui le prove che si possono fare per vedere all'opera il normalizzatore, ma le lascio al lettore come utile esercizio per la comprensione delle reti e dello scrubbing. PARTE III Real World: unclean, il sanity check di IPTables ================================================ Per concludere facciamo una breve panoramica sulla normalizzazione eseguita da IPTables, evitando di ripetere i concetti già espressi nella trattazione di PF e OpenBSD. All'interno di IPTables è il modulo Unclean che si occupa della normalizzazione, anche se in questo caso, forse, è più corretto parlare di sanity check. Per poter usufruire delle funzionalità di unclean occorre caricare il modulo usando l'opzione "-m unclean" all'interno della regola che comprende il traffico che si vuole normalizzare, ad esempio: iptables -A INPUT -i eth0 -m unclean -j DROP non sono previste opzioni per tale modulo. L'unico scopo del modulo unclean è quello di individuare i pacchetti sospetti, e a tale proposito sono implementati una serie di check che operano sui diversi protocolli. In dettaglio le funzioni che si occupano dei suddetti controlli sono check_icmp, check_udp, check_tcp e check_ip definite nel file /net/ipv4/netfilter/ipt_unclean.c all'interno del kernel di Linux [6]. Le operazioni eseguite da queste funzioni sono quelle elencate nella prima parte di questo articolo, alcune le abbiamo viste in dettaglio nella descrizione di scrub, ed in sostanza restano ancora valide per IPTables. Conclusioni =========== Abbiamo visto che la direttiva scrub di PF e il modulo unclean di IPTables (che ad essere precisi, non è un normalizzatore nel vero senso del termine), non sono confrontabili per funzionalità e stabilità (il modulo unclean è ancora indicato come "experimental"). Abbiamo anche visto che basta un dispositivo, relativamente semplice, per evitare numerosi grattacapi ai NIDS e ai firewall, ma anche alle normali applicazioni; è anche chiaro che messo da solo a guardia di una rete, un normalizer, serve davvero a ben poco. Riferimenti =========== [1] "Insertion, Evasion and Denial of Service: Eluding Network Intrusion Detection", T.H.Ptacek, T.N.Newsham http://www.securityfocus.com/data/library/ids.ps [2] La parte dei sorgenti del kernel di OpenBSD relativa al Packet Filter http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/ [3] Le faq ufficiali di OpenBSD http://www.openbsd.org/faq/pf/ [4] "Network Intrusion Detection: Evasion, Traffic Normalization, and End-to-End Protocol Semantics", M.Handley, V.Paxson, C.Kreibich http://www.icir.org/vern/papers/norm-usenix-sec-01-html/index.html [5] "Transport and Application Protocol Scrubbing" G.R.Malan, D.Watson, F.Jahanian http://www.ieee-infocom.org/2000/papers/340.ps [6] I sorgenti del kernel di Linux http://www.kernel.org/pub/linux/ [7] Request for Comments http://www.ietf.org/rfc/ RFC0791: Internet Protocol Specification RFC0793: Transmission Control Protocol Specification RFC2460: Internet Protocol, Version 6 (IPv6) Specification RFC2675: IPv6 Jumbograms [8] Nemesis Project http://www.packetfactory.net/projects/nemesis/ [9] TcpDump http://www.tcpdump.org/