echo ”Intelligenza e' la capacita' di evitare di fare un lavoro, ottenendo tuttavia di trovarlo finito” » /dev/OpenSource
Costruzione di uno sniffer, cosa serve? bah…. poca robba un pc e un compilatore gcc.
Per la realizzazione di questo sniffer useremo le comodissime librerie pcap, prima di scrivere il codice, vediamo quelle che sono le funzioni messe a disposizione dalle pcap lib. Le principali funzioni di questa libreria permettono con una facilità estrema di cercare e trovare un device di rete, inteso come network adapter, impostarlo in modalità promiscua (in modo diverso rispetto alla chiamata ioctl()(man ioctl), gestire filtri potenti e flessibili, selezionare grazie ai filtri il traffico da analizzare, analizzare pacchetto per pacchetto. Permette inoltre un'ottima gestione degli errori, quindi un buon livello di debug.
Funzioni principali
char *pcap_lookupdev(char *errbuf);
La funzione pcap_lookupdev cerca e restituisce un puntatore con il primo device di rete che trova ovviamente si puo forzare il device che si vuole. L'argomento errbuf è semplicemente un buffer utilizzato per contenere errori.Ah se la parola puntatore vi lascia un pò così <gapil.truelite.it/index.html>
int pcap_lookupnet(char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, char *errbuf);
La funzione pcap_lookupnet parla da se:),analizza il device è restituisce mask e network associati al device,bpf_u_int32 *netp e bpf_u_int32 *maskp sono i puntatori che indicano rispettivamente quando detto prima.
pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *errbuf);
La funzione pcap_open_live serve per aprire ed impostare un device in modalità promiscua e restituisce un packet capture descriptor pcap_t *(puntatore a file), un descrittore che si utilizzerà per accedere al device. snaplen indica il valore massimo di byte da catturare, to_ms invece è un read timeout.
con queste prime funzioni si prepare l'host sniffing a masticare pachetti di un'intera lan su qualsiasi protocollo,porta e ip, per ottenere un filtraggio più dettagliato e mirato abbiamo le seguenti funzioni
int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask);
con questa funzione prepariamo il filtraggio specificando cosa filtrare in char *str, del tipo se assegnamo la stringa char *str=“tcp” filtreremo solo ciò che protocollo 6
int pcap_setfilter(pcap_t *p, struct bpf_program *fp);
La funzione pcap_setfilter imposta nella struttura bpf_program i filtri.Rendendo cosi effetive le impostazioni di filtraggio impostate con la funzione pcap_compile
int pcap_stats(pcap_t *p, struct pcap_stat *ps)
Molto utile per sapere quanti pachetti sono stati catturati quanto droppati dal kernel etc etc, per avere delle statistiche sul traffico in e out
void pcap_close(pcap_t *p)
I filtri sono una delle caratteristiche più interessanti ed efficaci che ci offre libpcap. pcap_compile e pcap_set_filter si appoggiano alla struttura bpf_program e compilano i filtri attraverso BPF. Berkeley Packet Filtering è una macchina virtuale gestita a livello del kernel che si divide in due componenti: network tap e packet filter. Network tap è un device che prende in consegna il pacchetto ed il packet filter si occupa di controllare eventuali restrizioni: se i filtri lo consentono BPF consegna il pacchetto al protocollo applicativo.
Abbiamo visto che i filtri vengono gestiti dalle pcap come semplici stringhe. Le espressioni per il matching dei pacchetti sono:
le pcap lib usano le System call socket (man socket),quindi quano si andrà a settare il promisc mode usando setsocketopt anzichè ioctl, il normale ifconfig che usa ioctl non noterà che il device è in promisc mode, ovviamente si puo sempre risalire a device in promisc mode, ma meno facilmente.
Costruiamo il nostro sniffing vediamo le strutture principali cominciamo con l'analizzare la struttura in main.h
/** * @i32 bpf_int32 netmask * @i32 bpf_int32 address ip * @device device name * @fd file descriptor pcap session * upDevice method invoca la funzione pcap_lookupdev * @setPromisc method invoca pcap_open_live * @filterIn method invoca pcap_compile * @filterSet method invoca pcap_setfilter * @upNet method invoca pcap_lookupnet * @start method invoca pcap_loop * @stats method invoca pcap_stat * @end method invoca pcap_close */ struct _sniff { i32 netmask; i32 network; char *device; pcap_t *fd; int snaplen; struct ethpacket packet; struct bpf_program fp; struct pcap_pkthdr hdr; char *(*upDevice)(char *); pcap_t * (*setPromisc)(char*); int (*filterIn)(void); int (*filterSet)(void); int (*upNet)(char *); int (*start)(pcap_handler); int (*stats)(struct pcap_stat *); void (*end)(void); }
con questa struttura creiamo una sorte di classe dove le varibili servono a memorizzare tutte le informazioni ricevute dalle chiamate alle funzioni libpcap, mentre i puntatori funzione lincano le funzioni della pcaplib direttamente, cosi avremò un'entità con tutte le informazioni relative al nostro device,rete,netmask etc, il tipo i32 è una (#define bpf_u_int32 i32).
La seconda entità è una struttura di controllo per la gestione della stampa, della selezione dei pachetti da catturare
control.h
.................... ................ /** * @packet ethpacket * @iphdr tmp header ip * @tcphdr tmp header tcp * @store method for store packet sniffed * @type_sniff method for verify proto * @printf_header method for print header * @print_data method for print data */ struct _control { struct ethpacket packet; struct iphdr *ip; struct tcphdr *tcp; void (*store)(u_char*); int (*type_sniff)(int); void (*print_header)(void); void (*print_data)(void); };
queste strutture vengono inizzializzate in init.c, qui vengono lincate le funzioni richiamate nelle nostre entità
init.c
void init_sniff(sniff *mySniff) { mySniff->network=0; mySniff->netmask=0; mySniff->snaplen=1024; memset(&mySniff->fp,0,sizeof(struct bpf_program)); memset(&mySniff->hdr,0,sizeof(struct pcap_pkthdr)); mySniff->upDevice=pcap_lookupdev; mySniff->setPromisc=setPromisc; mySniff->filterIn=filterIn; mySniff->filterSet=filterSet; mySniff->upNet=upNet; mySniff->start=start; mySniff->stats=stats; mySniff->end=end; } void init_control(void) { Control.print_header=print_header; Control.print_data=print_data; Control.type_sniff=type; Control.store=store; Control.ip=(struct iphdr *)((unsigned long)(&Control.packet.ip)-2); Control.tcp=(struct tcphdr *)((unsigned long)(&Control.packet.tcp)-2); }
Per tener traccia di tutte le connessioni che andiamo a sniffare, usiamo una lista, per la creazione e la gestione delle liste usiamo le librerie GLIB, nel source user_speak.h dichiariamo tutti i prototipi di funzione
user_speak.h
struct _dhost { unsigned long int saddr; unsigned long int daddr; unsigned short int sport; unsigned short int dport; int connect; }; typedef struct _dhost dhost; dhost *create(unsigned long int,unsigned long int,unsigned short int,unsigned short int,int); static gint list_compare(dhost*,dhost*); GList *insert(dhost *); GList *remove_host(dhost *); GList *find(dhost *); void freehost(void);
……………………………da completare———- qui i sorgenti completi download sniff.tar.gz _sniff