Programmare con le Raw Socket
2002-04-25
When I was 16, I used to write articles under the nicknames Esorcista and XpTerminator.
The following is an article I translated from English to Italian, that got published on the 7th issue of OndaQuadra, an Italian e-zine.
+--------------------------------------------------------------------------+
| ONDAQUADRA ~ [MiSC] #06 - 25/04/2002 |
| PR0GRAMMARE LE REW S0CKET (TRADUZi0NE) [XpTerminator] 0x11/0x1D |
+--------------------------------------------------------------------------+
| |
| -==============================- |
| | Programmare le raw socket | |
| | Nitr0gen | |
| =/____________________________\= |
| | traduzione by XpTerminator | |
| -==============================- |
| |
| Premetto innanzi tutto che questo testo non e` di mia fattura, io ho |
| effettuato la traduzione dalla lingua inglese e delle modifiche ed |
| aggiunte per rendere il testo più chiaro; visto che in lingua |
| italiana non si trovano documenti del genere, ed essendo |
| interessante, ho ritenuto utile effettuarne la traduzione. |
| |
| Exile 2000 International Coding Team |
| (http://www.exile2k.org) |
| Documentation about native raw socket programming |
| All rights reserved Exile Team |
| |
| Free to distribute this text just keep it's integrity |
| Ripping is lame remember this |
| |
| |
| Per domande e commenti: (in english! ;) |
| |
| Nitr0gen |
| nitr0gen@hackersnews.com |
| |
| oppure: (in italiano:) |
| |
| XpTerminator |
| xp_terminator@katamail.com |
| |
| |
| |
| -----[ Prefazione ]--- |
| |
| |
| A differenza di come pensano molte persone, |
| programmare le raw socket non è annoiante ed una |
| perdita di tempo, anzi è una buona esperienza per |
| imparare ed a volte è molto utile. Programmando le |
| raw socket si ha molta più flessibilità rispetto ai |
| programmi che utilizzano socket con librerie standard |
| e quindi diventa facile implementare nuovi protocolli |
| e controllare cosa sta realmente accadendo anche al |
| più basso dei livelli. |
| Costruire pacchetti tramite una libreria è efficiente, |
| ma immagina quanto lo sia tramite una TUA libreria. |
| Non mi trovo qui per spiegare quanto sia figo o |
| potente programmare le raw socket, quindi vado |
| direttamente al dunque. Prima di tutto, voglio |
| avvertire che per poter comprendere al meglio questo |
| testo bisogna avere una buona conoscenza del C e della |
| struttura della rete. |
| Nella prima parte del testo introdurrò l'header ip, |
| l'header tcp, quello udp ed infine quello icmp, ultimo |
| non per importanza. |
| |
| La seconda parte di questa prefazione è dedicata ai |
| lamer: per favore abbiate rispetto dell'autore del |
| testo (Nitr0gen) e non rippate queso testo per vostri |
| scopi! |
| |
| Nitr0gen and Exile 2000 International Coding Team: |
| don't worry! i've only translated your document, |
| and i've riported this! |
| |
| |
| |
| |
| |
| |
| -----[ Indice ]--- |
| |
| |
| |
| |
| [ Header Ip ] |
| - Teoria |
| - Frammentazione |
| - Checksum |
| - Esempi |
| |
| [ Header Tcp ] |
| - Teoria |
| - Esempi |
| |
| [ Header Udp ] |
| - Teoria |
| - Esempi |
| |
| [ Header Icmp ] |
| - Teoria |
| - Esempi |
| |
| [ Implementazione ] |
| |
| [ Conclusioni ] |
| |
| [ Appendice A ] |
| - Strutture e Funzioni |
| - Codici sorgente |
| |
| [ Riferimenti ] |
| |
| [ Ringraziamenti ] |
| |
| |
| |
| |
| [ CAPITOLO 1 ] |
| (HEADER IP) |
| |
| |
| ---[ Teoria |
| |
| |
| Bene, se sei interessato nella programmazione delle |
| raw socket presumo che tu conosca le basi del tcp/ip. |
| L'header IP fa parte del layer di rete della suite di |
| protocolli tcp/ip. Fondamentalmente l'header ip è usato |
| per routare i pacchetti attraverso una rete,come internet |
| una wan o una lan. Il metodo di trasmissione di questo |
| header è inaffidabile poichè non hai garanzia dell'arrivo |
| a destinazione del pacchetto, o meglio, quando invii |
| dei pacchetti, non hai la certezza che questi arrivino a |
| destinazione nel giusto ordine in cui li hai inviati. |
| Prendi per esempio i pacchetti A B. A viene inviato prima |
| di B, ma non è garantito che A prenderà la stessa strada |
| (routing) di B per arrivare a destinazione. Il risultato |
| di ciò è quello che ho detto prima, i pacchetti non |
| vengono ricevuti nello stesso ordine di partenza. Come ho |
| ho detto dalla partenza, questo testo non è un corso di |
| tcp/ip ma un testo sulla programmazione, quindi, mi |
| limiterò alla programmazione. A titolo di informazione, |
| quando costruisci un pacchetto non dimenticare htons() o |
| htonl() per rispettare il giusto ordine dei byte. |
| Dei lettori si staranno sicuramente chiedendo perchè sto |
| dicendo questo, rispondo dicendo che io ho passato un |
| mese per risolvere questo piccolo problema. |
| |
| |
| |
| |
| Questa è una rappresentazione ascii dell'header ip: |
| |
| |
| 0 15-16 31 |
| +-----+-----+-----------+-----------------------+ \ |
| | Ver | IHL | TOS | Total Length | \ |
| | (4) | (4) | (8) | (16 ) | | |
| +-----+-----+-----------+--------+--------------+ | |
| | Identification | Flags | Frag Offset | | |
| | (16) | (3) | (13) | | |
| +-----------+-----------+--------+--------------+ | |
| | TTL | Protocol | Header Checksum | 20 Bytes |
| | (8) | (8) | (16) | | |
| +-----------+-----------+-----------------------+ | |
| | Source Ip Address | | |
| | (32) | | |
| +-----------------------------------------------+ | |
| | Destination Ip Address | | |
| | (32) | / |
| +-----------------------------------------------+ / |
| < Options > |
| > (if any) < |
| +-----------------------------------------------+ |
| > < |
| < Data > |
| > < |
| |
| |
| |
| Version (4 bits): |
| Il campo version è usato per indicare la |
| versione del IP (Internet Protocol), quindi o IpV4 |
| o IpV6. |
| |
| |
| IHL (Internet Header Length, 4 bits): |
| Il campo ihl indica la lunghezza dell'header |
| Ip. Quando non si usano opzioni, il valore di default |
| dovrebbe essere 5. |
| |
| |
| TOS (Type Of Service, 8 bits): |
| Tos è utilizzato per specificare le necessità |
| del servizio. |
| |
| Vi sono 4 opzioni per TOS: |
| |
| *NOME* *Valore esadecimale* |
| |
| 1- Minimize delay 0x10 |
| 2- Maximize throughput 0x08 |
| 3- Maximize reliability 0x04 |
| 4- Minimize monatary cost 0x02 |
| |
| 1: Questa opzione è utilizzata da applicazioni |
| che trasmettono piccole quantità di dati e |
| necessitano di una risposta veloce. |
| |
| 2: Caso opposto: questo è usato da applicazioni |
| che trasmettono grandi quantità di dati. |
| |
| 3: Non ne parlerò in questo testo. |
| |
| 4: Non ne parlerò in questo testo. |
| |
| Dato che TOS è una caratteristica sperimentale |
| dell'ip, non ci dilungheremo su di esso in questo |
| testo. |
| |
| |
| Total Length (8 bits): |
| Questo specifica la grandezza del datagramma, |
| (header + dati). Per esempio: |
| Prendiamo un pacchetto (ip header + tcp header[syn]) |
| senza dati. La grandezza dell'header ip è 20 e quella |
| dell'header tcp anche, quindi il campo tot_len sarà 40. |
| |
| |
| Identification (16 bits): |
| Id è utilizzato per identificare i frammenti. |
| Quando un pacchetto non è frammentato questo campo |
| è inutile. L'Id solitamente aumenta da datagramma a |
| datagramma; ogni frammento ha lo stesso id del |
| datagramma a cui appartiene. |
| |
| |
| Flags (3 bits): |
| Questo campo dell'header ip è utilizzato dalla |
| frammentazione. Ci sono 4 flag: |
| |
| *NOME* *Valore esadecimale* |
| |
| No flags 0x00 |
| More fragment 0x01 |
| Don't fragment 0x02 |
| More and Dont't frag 0x03 |
| |
| More fragment significa che ci sono ancora frammenti |
| dopo questo datagramma, don't fragment dice che il |
| pacchetto non è frammentato. Quando un datagramma è |
| frammentato,l'ultimo frammento non ha mai il flag MF |
| (More Fragment) settato. |
| |
| |
| Fragment Offset (13 bits): |
| Questo è l'offset con il quale il pacchetto |
| è stato calcolato. Il primo datagramma ha offset 0. |
| Questo campo è calcolato a 64 bits. Quando si calcola |
| l'offset, l'ultimo offset sarà uguale a tot_len. |
| |
| |
| TTL (Time To Live, 8 bits): |
| Questo campo specifica quanti hop potrà |
| effettuare il datagramma. Esso è decrementato ogni |
| volta che viene rispedito (durante il routing: ogni |
| router decrementa di 1 questo valore). Quando il TTL |
| raggiunge 0, il datagramma viene ignorato e viene |
| inviato al mittente un messaggio icmp di TIME EXCEED. |
| Questo avviene per evitare che un datagramma giri |
| all'infinito per la rete. |
| |
| |
| Protocol (8 bits): |
| Questo campo specifica il protocollo per il |
| layer di trasmissione. Il valore può essere: |
| |
| *NOME* *Valore esadecimale* |
| |
| IPPROTO_TCP 0x06 |
| IPPROTO_UDP 0x11 |
| IPPROTO_ICMP 0x01 |
| |
| Vi sono anche altri protocolli ma non saranno trattati |
| in questo testo. Per maggiori informazioni osserva il |
| seguente file header che definisce tutte le costanti. |
| '/usr/include/linux/in.h' |
| |
| |
| Header CheckSum (16 bits): |
| Il checksum è utilizzato per verificare |
| l'integrità di un datagramma. Se i dati durante |
| il trasporto si sono corrotti o modificati,esso |
| è in grado di capirlo. Se il checksum non viene |
| specificato nel datagramma, questo viene |
| scartato senza alcun tipo di avvertenza. Dal |
| punto di vista del programmatore ciò risulta |
| annoiante.Osserva l'appendice A per la funzione |
| del checksum ( in_cksum() ). |
| |
| |
| Source Ip (32 bits): |
| L'indirizzo ip dell'host che ha inviato il |
| datagramma. |
| |
| Destination Ip (32 bits): |
| L'indirizzo ip della macchina a cui dovrà |
| essere "recapitato" questo datagramma. |
| |
| |
| Options (Variable): |
| Il campo options non sarà trattato in |
| questo testo. |
| |
| |
| |
| Dal punto di vista della programmazione, costruire |
| un header ip significa semplicemente riempire una struttura. |
| Dato che sto utilizzando Linux, tutti i riferimenti che farò |
| a file di sistema saranno basati su kernel 2.2.13. |
| |
| |
| |
| |
| ---[ Frammentazione |
| |
| |
| In parole povere, la frammentazione avviene |
| quando il MTU (Maximum Transfert Unit) è minore della |
| lunghezza totale del datagramma, quindi, dovremo |
| dividere il datagramma in piccoli pezzi, ed inviarli |
| uno alla volta; quando i pacchetti saranno ricevuti, |
| il datagramma originale sarà ricostruito. |
| Quando effettuiamo la frammentazione,abbiamo bisogno di |
| settare campi specifici dell'header Ip. |
| Il flag MF deve essere settato a tutti i frammenti, |
| tranne l'ultimo.L'offset del primo pacchetto sarà zero. |
| L'Id dovrà essere lo stesso per ogni frammento, per |
| identificare a quale serie di pezzi di datagramma |
| appartiene.Se l'header Ip è modificato anche in un solo |
| frammento il checksum dovrà essere ricalcolato. La |
| lunghezza totale dei frammenti prenderà il valore del |
| MTU. |
| |
| |
| |
| |
| ---[ Checksum |
| |
| |
| Calcolare il checksum di un header non è |
| difficile, osserva l'appendice A per vedere la funzione |
| responsabile di questa operazione. |
| Questo è il prototipo della funzione: |
| |
| unsigned short in_cksum(unsigned short *addr, int len); |
| |
| - unsigned short *addr : E' un puntatore all'header ip. |
| - int len : E' la lunghezza dell'header ip. |
| |
| |
| |
| |
| |
| |
| |
| ---[ Esempi |
| |
| |
| Il nome della sezione dice esplicitamente cosa |
| troverai qui. |
| |
| |
| |
| /*******************************************************************/ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un header IP */ |
| /* SENZA FRAMMENTAZIONE */ |
| /* */ |
| /*******************************************************************/ |
| |
| void buildip_nf(){ /*** Funzione che costruisce un Header Ip ***/ |
| |
| struct iphdr *ip; |
| /*** A little step for a man, a big step for human kind ***/ |
| |
| ip = (struct iphdr *) malloc(sizeof(struct iphdr)); |
| /*** Alloca la memoria dinamica ***/ |
| |
| ip->ihl = 5; /*** Lunghezza in byte dell'Header IP ***/ |
| ip->version = 4; /*** Versione del protocollo IP ***/ |
| ip->tos = 0; /*** Sperimentale (Vedi sopra per i dettagli) ***/ |
| ip->tot_len = sizeof(struct iphdr) + 452 /*** Lunghezza totale del ***/ |
| /*** pacchetto ***/ |
| |
| |
| ip->id = htons(getuid()); |
| /*** ID (identification) del pacchetto, inutile nel nostro caso ***/ |
| |
| ip->ttl = 255; /*** Il pacchetto può effettuare |
| 255 hop ***/ |
| ip->protocol = IPPROTO_TCP; /*** Utilizziamo il tcp come protocollo |
| di trasmissione ***/ |
| ip->saddr = inet_addr("127.0.0.1"); /*** Ip sorgente ***/ |
| ip->daddr = inet_addr("127.0.0.1"); /*** Ip di destinazione ***/ |
| |
| ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr)); |
| /*** Checksum ***/ |
| |
| } |
| |
| |
| |
| |
| /*****************************************************************/ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un header IP */ |
| /* FRAMMENTAZIONE del pacchetto */ |
| /* in 2 frammenti */ |
| /* MTU = 280 byte */ |
| /* */ |
| /*****************************************************************/ |
| |
| |
| |
| void buildip_f(){ |
| /*** Funzione che costruisce un header IP frammentato ***/ |
| |
| struct iphdr *ipf; |
| |
| ipf = (struct iphdr *) malloc(sizeof(struct iphdr)); |
| |
| /**** PRIMO FRAMMENTO ***/ |
| ipf->ihl = 5; /*** Lunghezza dell'header in 32 bit */ |
| ipf->version = 4; /*** Versione del protocollo IP */ |
| ipf->tos = 0; /*** TOS (Type of service), inutilizzato */ |
| ipf->tot_len = sizeof(struct iphdr) + 256; /* Lunghezza del |
| primo frammento */ |
| ipf->id = htons(1); /*** Per identificare i nostri 2 frammenti */ |
| ipf->ttl = 255; /*** Il datagramma può effettuare 255 hop */ |
| ipf->protocol = IPPROTO_TCP; /*** uso il protocollo TCP */ |
| ipf->saddr = inet_addr("127.0.0.1"); /*** Ip sorgente (localhost) */ |
| ipf->daddr = inet_addr("127.0.0.1"); /*** Ip di destinazione |
| (localhost) */ |
| ipf->frag_off = htons(0x2000); /*** Offset 0 e MF */ |
| ipf->check = in_cksum((unsigned short *)ipf,sizeof(struct iphdr)+256); |
| /*** Checksum */ |
| |
| |
| /**** Qui dovremmo inviare il primo frammento ***/ |
| |
| |
| /**** SECONDO FRAMMENTO ***/ |
| ipf->tot_len = sizeof(struct iphdr) + 196; /*** Aggiorno la lunghezza |
| dei datagrammi */ |
| ipf->frag_off = htons(32); /*** Offset del frammento ***/ |
| ipf->check = in_cksum((unsigned short *)ipf,sizeof(struct iphdr)+196); |
| /*** Ricalcoliamo il checksum dato che abbiamo cambiato dei campi */ |
| |
| /**** Qui dovremmo inviare il secondo frammento ***/ |
| |
| } |
| |
| |
| [ CAPITOLO 2 ] |
| (HEADER TCP) |
| |
| |
| |
| |
| ---[ Teoria |
| |
| |
| Diamo ora un'occhiata all'header tcp. Dato |
| he esso fa utilizzo di un metodo di trasmissione |
| ffidabile, prima di effettuare lo streaming dei |
| ati c'è bisogno di creare una connessione. Quindi, |
| os'è una connessione? Con il tcp noi la chiamiamo |
| hree-way-handshake ("stretta di mano" in tre fasi). |
| on il primo passo il client invia al server un |
| acchetto tcp SYN per sincronizzare (SYNchronize) |
| l numero di acknowledgment; con il secondo passo |
| l server "riconosce" (ACKnowledge) il syn, cioè |
| onferma la sua ricezione, tramite un pacchetto |
| YN_ACK. Se il SYN_ACK non è ricevuto dal client lo |
| tato della connessione tcp rimane in SYN_SENT e |
| l client continua l'invio di SYN al server, |
| inchè esso non lo riceverà e quindi confermerà |
| on SYN_ACK.Dopo la conferma dell'avvenuta ricezione |
| el SYN, il client risponde con un ACK per |
| onfermare l'avvenuta ricezione del SYN_ACK. |
| eoricamente una connessione è creata tra due host, |
| a se il server si disconnette prima di ricevere il |
| ostro ultimo pacchetto (ACK), noi crederemo di |
| ssere connessi, ma in realtà non lo siamo. Questo è |
| no dei problemi del tcp. Il Tcp (Transfer control |
| rotocol) come l'Ip ( Internet protocol ) ha un |
| hecksum per il controllo dell'integrità dei dati |
| he fa utilizzo di uno pseudo-header di cui |
| arleremo dopo. Per essere sicuri che un pacchetto |
| rovenga realmente dal source ip specificato nel |
| uo header, il tcp ha aggiunto la funzionalità di un |
| equence number, ciò significa che durante |
| 'handshake, prima il client invia un Seq Number,poi |
| l server effettua l'acknowledgement del SYN con il |
| roprio seq number. Il server attende nel successivo |
| acchetto del client il seq number come specificato |
| el campo ACK dell'ultimo pacchetto inviato. Ciò |
| reviene l'hijacking o lo spoofing di una |
| onnessione da parte di utenti malintenzionati. |
| cco un esempio: |
| |
| Host A < ---- TCP CONNECTION ----> HOST B |
| |
| ^---- HOST X (utente malintenzionato) |
| |
| Se non ci fosse il sequence number, HOST X |
| potrebbe inviare pacchetti a HOST B facendo |
| credere in realtà che questi provenghino da |
| HOST A. Oggi giorno, con la generazione del |
| sequence number ormai casuale questa tecnica è |
| quasi impossibile. |
| |
| uesto protocollo ha ancora altre opzioni in ambito |
| i sicurezza aggiunte a quelle dell'IP, ma non |
| erranno trattate in questo testo. Il Tcp permette |
| noltre un buon managing dei pacchetti in entrata |
| d in uscita. Grazie alla specifica nei pacchetti |
| elle porte sorgente e destinazione, molti processi |
| ossono comunicare contemporaneamente. Tutte queste |
| pzioni, incluse quelle non trattate, però hanno lo |
| vantaggio di diminuire la velocità di trasmissione. |
| i sei mai domandato cosa sia un socket? Il termine |
| ocket nel mondo tcp è usato spesso. Questo è |
| emplicemente un indirizzo ip combinato con un numero |
| i porta, ed una coppia di socket è la combinazione |
| ndirizzo Ip Sorgente + Porta Sorgente + Indirizzo Ip |
| i Destinazione + Porta di Destinazione. |
| |
| Il Tcp ha 6 funzioni principali: |
| |
| |
| URG: Invia dei dati urgenti, cioè con |
| maggiore priorità, all'host di |
| destinazione. |
| |
| ACK: "Acknowledgement" dei dati ricevuti. |
| Come visto sopra. |
| |
| PSH: Invia i dati all'host di destinazione. |
| |
| RST: Resetta una connessione. |
| |
| SYN: Sincronizza il Seq Number. |
| |
| FIN: Nessun altro dato da inviare da parte |
| dell'host. |
| |
| |
| |
| |
| |
| |
| |
| |
| chema dell'header TCP: |
| |
| 15-16 31 |
| -----------------------+-----------------------+ \ |
| Source Port | Destination Port | \ |
| (16b) | (16b) | | |
| -----------------------+-----------------------+ | |
| Sequence Number | | |
| (32b) | | |
| -----------------------------------------------+ | |
| Acknowledgement | | |
| (32b) | | |
| -------+------+--------+-----------------------+ 20 Bytes |
| D_Off | Res | Flags | Windows | | |
| (4b) | (6b) | (6b) | (16b) | | |
| -------+------+--------+-----------------------+ | |
| Checksum | Urgent Pointer | | |
| (16b) | (16b) | | |
| -----------------------+------------+----------+ | |
| Options | Padding | | |
| (24b) | (8b) | / |
| ------------------------------------+----------+ / |
| DATA < |
| > |
| |
| |
| |
| |
| ource Port (16 bits): |
| La porta sorgente del pacchetto. |
| I pacchetti di ritorno saranno ricevuti su |
| questa porta. |
| |
| estination Port (16 bits): |
| La porta di destinazione del |
| pacchetto. Il pacchetto sarà ricevuto su |
| questa porta dall'host di destinazione. |
| |
| equence number (32bits): |
| Il Sequence number è una buona |
| caratteristica della sicurezza del tcp. |
| Quando un pacchetto viene ricevuto, il |
| modulo tcp del kernel verifica se il |
| numero è giusto. Se non lo è, il |
| pacchetto viene scartato. |
| |
| |
| |
| cknowledgment (32 bits): |
| Quando il flag ACK è settato, il |
| valore di questo campo è settato al |
| valore del Seq number che ci si aspetta |
| di ricevere nel prossimo pacchetto da |
| parte dell'altro peer (capo della |
| connessione). |
| |
| |
| ata Offset (4 bits): |
| L'offset dei dati espresso a 32 |
| bit. Se non vi sono opzioni, il valore di |
| default è 5. |
| |
| |
| eserved (6 bits): |
| Riservato per un uso futuro, deve |
| essere settato a 0. |
| |
| lags (6 bits): |
| Ci sono 6 flag possibili nel tcp. |
| Come visto sopra, questi sono: |
| |
| |
| URG: Indicatore di urgenza |
| ACK: Acknowledge |
| PSH: Push |
| RST: Reset |
| SYN: Sincronizza il Seq Number |
| FIN: Nessun altro dato da inviare |
| |
| |
| indows (16 bits): |
| Questo specifica il MSS (maximum |
| segment size) del prossimo pacchetto. Se un |
| pacchetto supera questo valore, esso dovrà |
| essere frammentato. |
| |
| |
| hecksum (16 bits): |
| Il checksum per verificare |
| l'integrità dei dati.Il checksum è calcolato |
| con uno Pseudo-Header che spiegherò. Questa |
| è la struttura, tratta da Tcp/Ip Volume 1 |
| (The protocol) di W. Richard Stevens. Per |
| favore dedica un minuto di silenzio per |
| questo incredibile uomo che è morto, è stato |
| uno straordinario scrittore. |
| |
| Questa è la struttura: |
| |
| struct pseudohdr { |
| unsigned long saddr; |
| unsigned long daddr; |
| char useless; |
| unsigned char protocol; |
| unsigned short length; |
| }; |
| |
| L'header contiene l'indirizzo ip sorgente e |
| destinazione per evitare pacchetti mal-routati |
| (saddr, daddr). Il carattere "useless" esiste |
| solo per rispettare il limite dei 32 bit |
| (per questo "useless" = "inutile"). "protocol" |
| contiene il protocollo, in questo caso |
| IPPROTO_TCP, e "lenght", la lunghezza del |
| pacchetto. |
| |
| Il checksum è calcolato come per l'header Ip: |
| |
| |
| -------------- CUT HERE ----------------- |
| |
| #define PSEUDO sizeof(struct pseudohdr) |
| #define TCPHDR sizeof(struct tcphdr) |
| |
| struct pseudohdr pseudo; |
| struct tcphdr tcp; |
| |
| pseudo.saddr = inet_addr("127.0.0.1"); |
| pseudo.daddr = inet_addr("127.0.0.1"); |
| pseudo.useless = htons(0); |
| pseudo.protocol = IPPROTO_TCP; |
| pseudo.length = TCPHDR + data; |
| |
| tcp->check = in_cksum((unsigned short *)&pseudo, PSEUDO+TCPHDR); |
| |
| -------------- CUT HERE ---------------- |
| |
| |
| |
| Urgent Pointer (16 bits): |
| Questo campo è significante solo se il flag |
| URG è settato. Esso punta ad un'area dati e ciò |
| rende i dati urgenti dal punto di vista dei peer. |
| |
| |
| Options (24 bits): |
| Il campo options non verrà trattato in |
| questo testo. |
| |
| |
| Padding (8 bits): |
| Il campo padding è riempito con 0. Questo |
| avviene per rispettare il limite dei 32 bit: esso |
| parte con 32 bit e finisce con 32 bit. |
| |
| |
| ---[ Esempi |
| |
| |
| |
| /******************************************************************/ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un header TCP */ |
| /* col flag SYN settato */ |
| /* e richiede una connessione telnet su localhost */ |
| /* */ |
| /******************************************************************/ |
| |
| |
| |
| |
| #define TCPHDR sizeof(struct tcphdr) |
| #define PSEUHDR sizeof(struct iphdr) |
| |
| |
| void build_tcp(){ |
| |
| struct tcphdr *tcp; /*** Header tcp ***/ |
| struct pseudohdr *pseudo; /*** Pseudo header ***/ |
| |
| if ((tcp = (struct tcphdr *) malloc(TCPHDR)) == NULL){ |
| perror("malloc()"); /*** Alloca la memoria dinamica ***/ |
| return -1; |
| } |
| |
| if ((pseudo = (struct pseudohdr *) malloc(PSEUDOHDR)) == NULL){ |
| perror("malloc()"); /*** Alloca la memoria dinamica ***/ |
| return -1; |
| } |
| |
| memset(tcp,'\0',TCPHDR); /*** Inizializza la memoria |
| al carattere \0 ***/ |
| memset(pseudo,'\0',PSEUDOHDR); |
| |
| |
| pseudo->saddr = inet_addr("127.0.0.1"); /*** Ip sorgente ***/ |
| pseudo->daddr = inet_addr("127.0.0.1"); /*** Ip di destinazione ***/ |
| pseudo->useless = 0; /*** Spazio riservato per rispettare il |
| limite ***/ |
| pseudo->protocol = IPPROTO_TCP; /*** Utilizziamo tcp ***/ |
| pseudo->length = htons(TCPHDR); /*** Dato che non abbiamo nessun |
| dato, la lunghezza è solo |
| quella dell'header tcp. ***/ |
| |
| |
| tcp->source = htons(5000); /*** Utilizziamo la 5000 |
| come porta sorgente ***/ |
| tcp->dest = htons(23); /*** Inviamo al demone telnet ***/ |
| tcp->seq = htonl(31337); /*** Initial sequence number ***/ |
| tcp->ack_seq = htonl(0); /*** E' significante solo se è settato |
| il flag ack ***/ |
| tcp->doff = 5; /*** Offset dell'header tcp a 32 bit ***/ |
| tcp->fin = 0; /*** Flag FIN non settato durante l'handshake ***/ |
| tcp->syn = 1; /*** Flag SYN settato, primo passo dell'handshake ***/ |
| tcp->rst = 0; /*** Flag RST non settato durante l'handshake ***/ |
| tcp->psh = 0; /*** Flag PSH non settato durante l'handshake ***/ |
| tcp->ack = 0; /*** Flag ACK non settato durante l'handshake ***/ |
| tcp->urg = 0; /*** Flag URG non settato durante l'handshake ***/ |
| tcp->window = htons(4000); /*** Lunghezza massima del prossimo |
| pacchetto ***/ |
| tcp->urg_ptr = htons(0); /*** E' significativo solo se il flag URG |
| è settato ***/ |
| |
| tcp->check = in_cksum((unsigned short *)pseudo,TCPHDR+PSEUDOHDR); |
| /*** Calcolo del checksum tcp per evitare corruzione dei dati ***/ |
| } |
| |
| |
| |
| |
| |
| |
| [ CAPITOLO 3 ] |
| (HEADER UDP) |
| |
| |
| |
| |
| ---[ Teoria |
| |
| |
| Arrivato fin qui, hai superato la parte più |
| "difficile". |
| L'Udp è meno complesso del tcp. Esso non ha |
| caratteristiche di sicurezza e neanche di affidabilità |
| ma ha un maggiore transfert rate che lo rende utile. |
| Come il tcp, anche l'udp ha un checksum ed ha bisogno |
| di uno pseudo header per calcolarlo. |
| |
| |
| Schema dell'Header UDP: |
| |
| |
| 0 15-16 31 |
| +-----------------------+-----------------------+ |
| | Source Port | Destination Port | |
| | (16 b) | (16 b) | |
| +-----------------------+-----------------------+ |
| | Length | Checksum | |
| | (16 b) | (16 b) | |
| +-----------------------+-----------------------+ |
| > DATA < |
| < > |
| |
| |
| |
| Source Port (16 bits): |
| La porta sorgente del datagramma. |
| I pacchetti di ritorno saranno ricevuti su |
| questa porta. |
| |
| |
| Destination Port (16 bits): |
| La porta destinazione del datagramma. |
| Il datagramma sarà ricevuto dal peer di |
| destinazione su questa porta. |
| |
| |
| Length (16 bits): |
| Contiene la lunghezza dei datagrammi |
| udp in ottetti, solitamente 8. |
| |
| |
| Checksum (16 bits): |
| Contiene il checksum del datagramma |
| per controllarne l'integrità e per |
| assicurare che non vi sono stati errori nel |
| routing. |
| |
| Se sei curioso circa la sua struttura, |
| osserva l'appendice A. |
| |
| |
| |
| |
| |
| ---[ Esempi |
| |
| |
| |
| |
| /****************************************************************/ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un header UDP */ |
| /* */ |
| /****************************************************************/ |
| |
| |
| void build_udp(){ |
| |
| struct udphdr *udp; /*** Dichiarazione delle variabili ***/ |
| struct pseudohdr pseudo; |
| |
| if ((udp = (struct udphdr *) malloc(sizeof(struct udphdr))) == NULL){ |
| perror("Memory exhausted"); /*** Allocazione memoria |
| dinamica ***/ |
| return ; |
| } |
| |
| |
| /*** Pseudo-Header, utilizzato per evitare datagrammi "mal-routati" ***/ |
| |
| pseudo.saddr = inet_addr("127.0.0.1"); /* Inviamo da localhost **/ |
| pseudo.daddr = inet_addr("127.0.0.1"); /* Inviamo a localhost **/ |
| pseudo.useless = htons(0); /* Per rispettare il limite |
| di 32 bit*/ |
| pseudo.protocol = IPPROTO_UDP; /* Utilizziamo il protocollo UDP */ |
| pseudo.length = sizeof(struct udphdr); /* sizeof della |
| struttura udphdr */ |
| |
| udp->source = htons(5000); /** Inviamo dalla porta 5000 */ |
| udp->dest = htons(7); /** Inviamo al server echo (porta=7) */ |
| udp->len = htons(sizeof(struct udphdr)); /* Lunghezza di udphdr. |
| Utilizziamo htons() |
| per il giusto |
| ordinamento dei byte */ |
| |
| udp->check = in_cksum((unsigned short *)&pseudo,sizeof(struct udphdr)); |
| /*** Calcoliamo il checksum ***/ |
| |
| } |
| |
| |
| [ CAPITOLO 4 ] |
| (HEADER ICMP) |
| |
| |
| |
| |
| ---[ Teoria |
| |
| |
| Fondamentalmente l'Internet Control Message |
| Protocol (ICMP) è utilizzato per riportare errori |
| come l'irraggiungibilità di un host,la scadenza del |
| TTL (Time to live) o "source quench" (letteralmente |
| "spegnimento" dell'host sorgente) che significa che |
| non c'è abbastanza memoria per proseguire l'invio |
| del datagramma in questione. Non esiste un |
| messaggio icmp per evitare cicli infiniti di un |
| pacchetto in una rete. |
| |
| |
| |
| Schema dell'Header ICMP: |
| |
| |
| 0 15-16 31 |
| +-----------+-----------+-----------------------+ |
| | Type | Code | Checksum | |
| | (8 b) | (8 b) | (16 b) | |
| +-----------+-----------+-----------------------+ |
| | UNUSED | |
| | (32 b) | |
| +-----------------------------------------------+ |
| | Internet Header + 64 bits di dati | |
| | (32 b) | |
| +-----------------------------------------------+ |
| Questo è il formato standard dell'header icmp. |
| Se però cambiano i valori dei campi "Type" e "Code" |
| il campo "unused" (inutilizzato) viene utilizzato. |
| Se "unused" rimane inutilizzato, settalo a 0. A |
| seconda del tipo di messaggio icmp, alcuni campi del |
| header Ip possono cambiare. |
| |
| |
| |
| ECHO REQUEST o ECHO REPLY |
| ------------------------- |
| |
| L'Echo viene comunemente chiamato PING. Per |
| generare la reply, lo stack inverte l'indirizzo Ip |
| sorgente e destinazione nell'header Ip. Il campo |
| "UNUSED" è diviso in campi da 8 bit ciascuno, chiamati |
| Identifier e Sequence number, che descriverò qui sotto. |
| |
| |
| TYPE (8 bits): |
| 0 Per echo reply |
| 8 Per echo request |
| |
| CODE (8 bits): |
| 0 Campo inutilizzato per questo tipo |
| di messaggi |
| |
| CHECKSUM (16 bits): |
| Il checksum è calcolato come per gli altri |
| header, ma il campo checksum deve essere 0 prima |
| di averlo calcolato. Per rispettare il limite dei |
| 32 bit, il kernel può "imbottire" il messaggio se |
| la sua lunghezza totale è inaspettata, cioè minore |
| dei 32 bit. |
| |
| Identifier (16 bits): |
| Questo campo si comporta allo stesso modo |
| dell'ID nell'headers ip, ma per gli echo e reply. |
| Esso aiuta a capire quale echo reply appartiene a |
| quale echo request (come per la frammentazione). |
| |
| Sequence Number (16 bits): |
| Questo campo si comporta allo stesso modo |
| dell'ID nell'headers ip, ma per gli echo e reply. |
| Esso aiuta a capire quale echo reply appartiene a |
| quale echo request (come per la frammentazione). |
| |
| |
| Negli echo request possono essere inseriti anche i dati, |
| questi poi saranno rispediti dall'host di destinazione |
| nell'echo reply. |
| |
| |
| |
| |
| DESTINATION UNREACHABLE |
| ----------------------- |
| |
| Questo messaggio è utilizzato per indicare |
| che un host o una rete è down, che un servizio non |
| è in funzione, che lo stack non supporta il |
| protocollo, che c'è bisogno della frammentazione ma |
| "don't fragment" (DF) è settato, o che c'è stato un |
| errore durante il routing del pacchetto. Il campo |
| "UNUSED" rimane inutilizzato e dovrebbe essere |
| settato a 0. |
| |
| |
| TYPE (8 bits): |
| 3 Destination Unreachable |
| |
| |
| CODE (8 bits): |
| 0 Rete irraggiungibile |
| 1 Host irraggiungibile |
| 2 Protocollo irraggiungibile |
| 3 Porta irraggiungibile |
| 4 Frammentazione necessaria ma DF settato. |
| 5 Routing fallito |
| |
| |
| |
| CHECKSUM (16 bits): |
| Il checksum è calcolato come |
| l'ultimo messaggio. |
| |
| |
| UNUSED (32 bits): |
| Rimane inutilizzato. |
| |
| |
| INTERNET HEADER + 64 BIT DI DATI DEL DATAGRAMMA: |
| Il titolo è esplicativo.E' usato |
| dai protocolli di livello più alto, se |
| c'è una porta da identificare o altri |
| campi. |
| |
| |
| |
| SOURCE QUENCH |
| ------------- |
| |
| Questo messaggio d'errore viene |
| inviato quando un host o un gateway non ha |
| abbastanza memoria per mettere in coda il |
| pacchetto ricevuto per inoltrarlo. |
| |
| |
| TYPE (8 bits): |
| 4 Source Quench |
| |
| |
| CODE (8 bits): |
| 0 Inutilizzato |
| |
| |
| CHECKSUM (16 bits): |
| Il checksum viene calcolato come |
| l'ultimo messaggio. |
| |
| |
| UNUSED (32 bits): |
| Rimane inutilizzato. |
| |
| |
| INTERNET HEADER + 64 BIT DI DATI DEL DATAGRAMMA: |
| Il titolo è esplicativo.E' usato |
| dai protocolli di livello più alto, se |
| c'è una porta da identificare o altri |
| campi. |
| |
| |
| |
| REDIRECT |
| -------- |
| |
| Un messaggio redirect (di redirezione) è |
| inviato quando esiste una strada più corta per |
| arrivare alla destinazione. |
| Esempio: |
| |
| Johnny invia un pacchetto alla rete R. La sua |
| route table (tabella di routing) dice per |
| default di inviarlo al Gateway #1, ma quando |
| il Gateway #1 riceve il pacchetto esso trova |
| una via più corta per arrivare alla |
| destinazione. Esso quindi invia un REDIRECT |
| all'ip sorgente specificando l'indirizzo Ip |
| del nuovo gateway nel campo UNUSED. |
| |
| |
| Vi è una eccezione quando l'"IP source routing" è |
| abilitato,ma di questa opzione dell'ip non ho parlato |
| in questo testo quindi mi fermo qui. |
| |
| |
| TYPE (8 bits): |
| 5 Redirect |
| |
| |
| CODE (8 bits): |
| 0 Redirige i datagrammi destinati ad una Rete |
| 1 Redirige i datagrammi destinati ad un Host |
| 2 Redirige i datagrammi destinati ad un TOS e |
| ad una Rete |
| 3 Redirige i datagrammi destinati ad un TOS e |
| ad un Host |
| |
| |
| CHECKSUM (16 bits): |
| Il checksum viene calcolato come |
| l'ultimo messaggio. |
| |
| |
| |
| GATEWAY INTERNET ADDRESS (32 bits): |
| Indirizzo Ip del gateway più vicino |
| al quale inviare il pacchetto. |
| |
| |
| INTERNET HEADER + 64 BIT DI DATI DEL DATAGRAMMA: |
| Il titolo è esplicativo. E' usato |
| dai protocolli di livello più alto, se |
| c'è una porta da identificare o altri |
| campi. |
| |
| |
| |
| TIME EXCEED |
| ----------- |
| |
| Questo messaggio viene inviato quando il Time To |
| Live (TTL)(tempo di vita) di un pacchetto scade o quando |
| scade il tempo per riassemblare il pacchetto. |
| |
| |
| TYPE (8 bits): |
| 11 Time Exceed |
| |
| |
| CODE (8 bits): |
| 0 Time To Live Scaduto (TTL) |
| 1 Tempo per il riassemblaggio dei frammenti |
| scaduto |
| |
| |
| CHECKSUM (16 bits): |
| Il checksum viene calcolato come |
| l'ultimo messaggio. |
| |
| |
| UNUSED (32 bits): |
| Rimane inutilizzato. |
| |
| |
| INTERNET HEADER + 64 BIT DI DATI DEL DATAGRAMMA: |
| Il titolo è esplicativo. E' usato |
| dai protocolli di livello più alto, se |
| c'è una porta da identificare o altri |
| campi. |
| |
| |
| |
| |
| PARAMETER PROBLEM |
| ----------------- |
| |
| Il messaggio "Parameter problem" |
| (problemi di parametri) è inviato quando un |
| datagramma ha valori errati nelle opzioni, |
| TOS o un campo non valido. Il campo UNUSED |
| viene riempito con un puntatore al campo |
| errato. |
| |
| |
| TYPE (8 bits): |
| 12 Parameter problem |
| |
| |
| CODE (8 bits): |
| 0 Rende il campo POINTER significativo, |
| cioè non viene ignorato |
| |
| |
| CHECKSUM (16 bits): |
| Il checksum viene calcolato come |
| l'ultimo messaggio. |
| |
| |
| POINTER (8 bits): |
| Viene preso in considerazione solo |
| se CODE = 0. Esso punta all'area dove si |
| trova l'errore. |
| |
| |
| UNUSED (24 bits): |
| Rimane inutilizzato. |
| |
| |
| INTERNET HEADER + 64 BIT DI DATI DEL DATAGRAMMA: |
| Il titolo è esplicativo. E' usato |
| dai protocolli di livello più alto, se |
| c'è una porta da identificare o altri |
| campi. |
| |
| |
| |
| |
| |
| TIMESTAMP REQUEST e TIMESTAMP REPLY |
| ----------------------------------- |
| |
| Tramite questi messaggi si comunica l'orario in |
| secondi in cui il pacchetto è stato modificato l'ultima |
| volta dalla mezzanotte UT (Universal Time). Quando il |
| pacchetto viene inviato, l'orario viene inserito, e |
| quando viene inviata la risposta a questo,viene inserito |
| l'orario affianco a quello precedente. Tramite questo |
| metodo possiamo calcolare quando sia distante da noi un |
| host. |
| |
| |
| TYPE (8 bits): |
| 13 Timestamp Request |
| 14 Timestamp Reply |
| |
| |
| CODE (8 bits): |
| 0 Rende l'ID e il Seq Num significativi |
| (non vengono ignorati) |
| |
| |
| CHECKSUM (16 bits): |
| Il checksum viene calcolato come |
| l'ultimo messaggio. |
| |
| |
| IDENTIFIER (16 bits): |
| Significativo solo se Code = 0. Esso |
| aiuta a determinare la giusta combinazione |
| reply / request. |
| |
| |
| SEQUENCE NUMBER (16 bits): |
| Significativo solo se Code = 0. Esso |
| aiuta a determinare la giusta combinazione |
| reply / request. |
| |
| |
| |
| NETMASK REQUEST e NETMASK REPLY |
| ------------------------------- |
| |
| Questo messaggio icmp restituisce la |
| maschera di rete dell'host che invia il messaggio. |
| Per generare la reply, gli indirizzi Ip sorgente e |
| destinazione vengono invertiti, viene inserito la |
| maschera di rete nel campo, viene ricalcolato il |
| checksum e viene spedito al mittente. Se il |
| mittente non conosce il proprio Ip, egli inserisce |
| 0 nel campo del source ip adress, e la risposta al |
| pacchetto verrà inviata all'indirizzo Ip di |
| broadcast. |
| |
| |
| |
| TYPE (8 bits): |
| 17 Netmask Request |
| 18 Netmaks Reply |
| |
| |
| CODE (8 bits): |
| 0 Rende l'ID e il Seq Num significativi |
| |
| |
| CHECKSUM (16 bits): |
| Il checksum viene calcolato come |
| l'ultimo messaggio. |
| |
| |
| IDENTIFIER (16 bits): |
| Significativo solo se Code = 0. Esso |
| aiuta a determinare la giusta combinazione |
| reply / request. |
| |
| |
| SEQUENCE NUMBER (16 bits): |
| Significativo solo se Code = 0. Esso |
| aiuta a determinare la giusta combinazione |
| reply / request. |
| |
| |
| |
| |
| |
| |
| ---[ Esempi |
| |
| |
| |
| |
| /****************************************************************/ |
| /* */ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un header ICMP (PING) */ |
| /* */ |
| /****************************************************************/ |
| |
| |
| |
| void icmp_build(){ |
| |
| struct icmphdr *icmp; |
| |
| icmp = (struct icmphdr *) malloc(sizeof(struct icmphdr)); |
| |
| icmp->type = ICMP_ECHO; /*** ECHO REQUEST */ |
| icmp->code = 0; /*** Campi Id e Sequence significativi */ |
| icmp->un.echo.id = 0; /*** Per identificare la risposta al ping */|
| icmp->un.echo.sequence = 0; /*** Per identificare la risposta al ping */ |
| icmp->checksum = 0; /*** Il campo checksum deve essere 0 |
| prima del calcolo */ |
| |
| icmp->checksum =in_cksum((unsigned short *)icmp,sizeof(struct icmphdr)); |
| /*** Checksum */ |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| [ CAPITOLO 5 ] |
| (IMPLEMENTAZIONE) |
| |
| |
| ---[ Teoria |
| |
| Dopo questa teoria sui vari header |
| dei protocolli, dobbiamo ora abbandonare la |
| teoria per passare alla implementazione vera |
| e propria. Fondamentalmente ciò che descrivo |
| in questo testo è come creare un socket |
| utilizzando il livello raw, come riempire |
| la struttura del socket e come comunicare ad |
| un livello così basso. |
| |
| Per prima cosa osserveremo man mano |
| un codice sorgente e per ogni linea |
| spiegherò il suo significato. Andiamo: |
| |
| |
| int sock, optval; /*** Descrittore del socket ***/ |
| struct sockaddr_in peer; /*** Struttura usata da sendto() ***/ |
| |
| |
| Se non capisci qualcosa, credo sia meglio |
| che tu prenda un libro sulla programmazione |
| dei socket su sistemi unix. |
| |
| if ((sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) == -1){ |
| perror("Errore nella creazione del socket"); |
| return -1; |
| } |
| |
| |
| Queste linee creano un socket utilizzando |
| il TCP come protocollo di trasporto. Il |
| socket è SOCK_RAW per permettere l'accesso |
| raw. E' utilizzato AF_INET poichè ci |
| troviamo su internet. Da ora, se socket() |
| restituisce un errore, perror() |
| visualizzerà il contenuto di errno e ciò |
| che ha restituito la funzione. |
| |
| setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int)); |
| |
| |
| |
| Questa funzione dice al socket sock che |
| lavoriamo al livello IPPROTO_IP e che noi |
| includeremo l'header ip (IP_HDRINCL) nei |
| pacchetti inviati. optval e sizeof(int) |
| non sono importanti per questa opzione, |
| quindi non parlerò di loro. |
| |
| |
| peer.sin_family = AF_INET; |
| peer.sin_port = htons(23); |
| peer.sin_addr.s_addr = inet_addr("127.0.0.1"); |
| |
| |
| Qui riempiamo la struttura sockaddr_in |
| (peer) utilizzata da sendto().Diciamo che è |
| un protocollo di famiglia Internet(AF_INET). |
| La porta di destinazione è la 23. |
| Utilizziamo htons() per la giusta sequenza |
| dei byte, come detto all'inizio. Nella |
| linea successiva settiamo l'indirizzo di |
| destinazione utilizzando inet_addr() per |
| convertire l'indirizzo in formato binario. |
| |
| A questo punto dovremmo costruire il nostro |
| pacchetto. Prenderò per scontato le cose |
| di cui ho parlato nella teoria. |
| |
| |
| sendto(sock, packet, strlen(packet),0, |
| (struct sockaddr *)&peer,sizeof(struct sockaddr)); |
| |
| |
| |
| Inviamo il pacchetto packet sul socket sock |
| per la lunghezza strlen(packet). Nel parametro |
| successivo settiamo 0, poichè non indichiamo |
| alcun flag. Vi sono 4 flag: |
| |
| MSG_OOB Questo invia un pacchetto |
| Out Of Bound, aumentando la sua |
| priorità. |
| |
| MSG_DONTROUTE Non osserva la tabella di |
| routing e invia direttamente |
| all'interfaccia. |
| |
| MSG_DONTWAIT Normalmente sendto() può |
| trattenere un pacchetto, ma con |
| questo flag, non lo farà e |
| restituirà EAGAIN. |
| |
| MSG_NONSIGNAL Chiede di non inviare il |
| segnale SIGPIPE quando uno stream |
| orientato alla connessione |
| fallisce cioè genera un errore o |
| si disconnette. |
| |
| |
| Poi, con ((struct sockaddr *)&peer), chiediamo |
| al peer di specificare la famiglia di |
| protocolli, e la porta e l'indirizzo di |
| destinazione poichè sendto si aspetta di |
| avere un puntatore alla struttura sockaddr. |
| Infine specifichiamo la lunghezza della |
| struttura sockaddr tramite |
| (sizeof(struct sockaddr)) e il datagramma è |
| inviato!! |
| |
| Per essere sicuro di aver capito, scrivi |
| questo esempio e prova a ricevere il |
| pacchetto e stamparne il risultato. Ho |
| creato dei programmini nella seguente |
| sezione in modo che tu possa verificare di |
| aver capito bene. |
| |
| Suggerimento: man recv |
| |
| buona fortuna |
| |
| |
| -----[ Conclusioni ]--- |
| |
| |
| |
| |
| Ho fatto il meglio che potevo per creare |
| un testo completo e buono sulla programmazione delle |
| raw socket. Spero che il testo ti sia piaciuto e sono |
| sicuro che ti abbia aiutato nel capire come codare |
| con le raw socket. Questo documento mi ha aiutato |
| a capire delle cose di cui non ero sicuro e ad |
| imparare delle cose che non avevo mai sentito prima. |
| Infine, vorrei approfittare di questo momento per |
| dire ufficialmente che in breve tempo rilascerò un |
| portscanner simile a nmap. Sto provando a migliorarne |
| la velocità e lo stile di codifica per renderlo più |
| leggibile a persone "ordinarie" come me. Questo |
| progetto è chiamato ESCAN ed include molte funzioni |
| come: connect scan, stealth, half open, decoys, |
| logging. Una versione beta dovrebbe essere rilasciata |
| il prima possibile. Per seguire lo sviluppo: |
| http://www.exile2k.org |
| |
| |
| |
| |
| [ Appendice A ] |
| (Strutture e Funzioni) |
| |
| |
| |
| |
| |
| |
| ---[ STRUTTURA HEADER IP |
| |
| |
| |
| struct iphdr { |
| |
| #if __BYTE_ORDER == __LITTLE_ENDIAN |
| unsigned int ihl:4; |
| unsigned int version:4; |
| #elif __BYTE_ORDER == __BIG_ENDIAN |
| unsigned int version:4; |
| unsigned int ihl:4; |
| #else |
| # error "Please fix <bits/endian.h>" |
| #endif |
| u_int8_t tos; |
| u_int16_t tot_len; |
| u_int16_t id; |
| u_int16_t frag_off; |
| u_int8_t ttl; |
| u_int8_t protocol; |
| u_int16_t check; |
| u_int32_t saddr; |
| u_int32_t daddr; |
| /*The options start here. */ |
| }; |
| |
| |
| |
| |
| |
| |
| ---[ STRUTTURA PSEUDO HEADER |
| |
| |
| |
| struct pseudohdr { |
| unsigned long saddr; |
| unsigned long daddr; |
| char useless; |
| unsigned char protocol; |
| unsigned short length; |
| }; |
| |
| |
| |
| |
| |
| ---[ STRUTTURA HEADER TCP |
| |
| |
| |
| |
| struct tcphdr { |
| __u16 source; |
| __u16 dest; |
| __u32 seq; |
| __u32 ack_seq; |
| #if defined(__LITTLE_ENDIAN_BITFIELD) |
| __u16 res1:4, |
| doff:4, |
| fin:1, |
| syn:1, |
| rst:1, |
| psh:1, |
| ack:1, |
| urg:1, |
| res2:2; |
| #elif defined(__BIG_ENDIAN_BITFIELD) |
| __u16 doff:4, |
| res1:4, |
| res2:2, |
| urg:1, |
| ack:1, |
| psh:1, |
| rst:1, |
| syn:1, |
| fin:1; |
| #else |
| #error "Adjust your <asm/byteorder.h> defines" |
| #endif |
| __u16 window; |
| __u16 check; |
| __u16 urg_ptr; |
| }; |
| |
| |
| |
| |
| |
| ---[ STRUTTURA HEADER UDP |
| |
| |
| |
| struct udphdr { |
| __u16 source; |
| __u16 dest; |
| __u16 len; |
| __u16 check; |
| }; |
| |
| |
| |
| |
| |
| ---[ STRUTTURA HEADER ICMP |
| |
| |
| |
| |
| struct icmphdr { |
| __u8 type; |
| __u8 code; |
| __u16 checksum; |
| union { |
| struct { |
| __u16 id; |
| __u16 sequence; |
| } echo; |
| __u32 gateway; |
| struct { |
| __u16 __unused; |
| __u16 mtu; |
| } frag; |
| } un; |
| }; |
| |
| |
| |
| |
| |
| ---[ FUNZIONE PER IL CALCOLO DEL CHECKSUM |
| |
| |
| |
| |
| /* |
| * in_cksum -- |
| * Checksum routine for Internet Protocol |
| * family headers (C Version) |
| */ |
| unsigned short in_cksum(unsigned short *addr, int len) |
| { |
| register int sum = 0; |
| u_short answer = 0; |
| register u_short *w = addr; |
| register int nleft = len; |
| |
| /* |
| * Our algorithm is simple, using a 32 bit accumulator (sum), we add |
| * sequential 16 bit words to it, and at the end, fold back all the |
| * carry bits from the top 16 bits into the lower 16 bits. |
| */ |
| while (nleft > 1) |
| { |
| sum += *w++; |
| nleft -= 2; |
| } |
| |
| /* mop up an odd byte, if necessary */ |
| if (nleft == 1) |
| { |
| *(u_char *) (&answer) = *(u_char *) w; |
| sum += answer; |
| } |
| /* add back carry outs from top 16 bits to low 16 bits */ |
| sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ |
| sum += (sum >> 16); /* add carry */ |
| answer = ~sum; /* truncate to 16 bits */ |
| return (answer); |
| } |
| |
| |
| |
| |
| |
| |
| |
| ----[ Codici sorgente |
| |
| |
| /********************************************************************/ |
| /* */ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione costruisce un pacchetto ICMP (PING) */ |
| /* includendo l'header IP */ |
| /* */ |
| /* */ |
| /* */ |
| /* */ |
| /********************************************************************/ |
| |
| |
| #include <stdio.h> |
| |
| #include <linux/ip.h> |
| #include <linux/icmp.h> |
| #include <netinet/in.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| |
| |
| |
| |
| unsigned short in_cksum(unsigned short *addr, int len); |
| |
| |
| int main(){ |
| |
| int sock, optval; |
| char *packet, *buffer; |
| |
| struct icmphdr *icmp; |
| |
| struct sockaddr_in peer; |
| struct iphdr *ip; |
| |
| |
| ip = (struct iphdr *) malloc(sizeof(struct iphdr)); |
| icmp = (struct icmphdr *) malloc(sizeof(struct icmphdr)); |
| packet= (char *) malloc(sizeof(struct iphdr) + sizeof(struct icmphdr)); |
| buffer= (char *) malloc(sizeof(struct iphdr) + sizeof(struct icmphdr)); |
| |
| |
| ip = (struct iphdr *) packet; |
| icmp = (struct icmphdr *) (packet + sizeof(struct iphdr)); |
| |
| |
| ip->ihl = 5; |
| ip->version = 4; |
| ip->tos = 0; |
| ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr); |
| ip->id = htons(getuid()); |
| ip->ttl = 255; |
| ip->protocol = IPPROTO_ICMP; |
| ip->saddr = inet_addr("127.0.0.1"); |
| ip->daddr = inet_addr("127.0.0.1"); |
| |
| |
| sock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); |
| setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int)); |
| |
| icmp->type = ICMP_ECHO; |
| icmp->code = 0; |
| icmp->un.echo.id = 0; |
| icmp->un.echo.sequence = 0; |
| icmp->checksum = 0; |
| |
| icmp->checksum = in_cksum((unsigned short *)icmp,sizeof |
| (struct icmphdr)); |
| |
| ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr)); |
| |
| |
| |
| peer.sin_family = AF_INET; |
| peer.sin_addr.s_addr = inet_addr("127.0.0.1"); |
| |
| sendto(sock,packet,ip->tot_len,0,(struct sockaddr *)&peer,sizeof |
| (struct sockaddr)); |
| |
| recv(sock,buffer,sizeof(struct iphdr)+sizeof(struct icmphdr),0); |
| printf("Ricevuto l'ECHO REPLY\n"); |
| |
| close(sock); |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| /********************************************************************/ |
| /* */ |
| /* Exile 2000 International Coding Team */ |
| /* (http://www.exile2k.org) */ |
| /* All rights reserved Exile Team */ |
| /* Copyright 2000 (C) Nitr0gen */ |
| /* */ |
| /* Questa funzione csotruisce un pacchetto UDP */ |
| /* includendo l'header IP ed inviandlo al server echo locale */ |
| /* */ |
| /* Per far funzionare il programma abilita il server echo: */ |
| /* */ |
| /* - pico /etc/inetd.conf */ |
| /* - Elimina i simboli del commento dalla riga */ |
| /* dell'echo server (udp one) */ |
| /* - killall -HUP inetd */ |
| /* */ |
| /* */ |
| /* */ |
| /* */ |
| /********************************************************************/ |
| |
| |
| #include <stdio.h> |
| |
| #include <linux/ip.h> |
| #include <linux/udp.h> |
| #include <netinet/in.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| |
| |
| |
| |
| unsigned short in_cksum(unsigned short *addr, int len); |
| |
| |
| |
| int main(){ |
| |
| int sock, optval; |
| char *packet, *buffer; |
| |
| struct udphdr *udp; |
| struct pseudohdr { |
| unsigned long saddr; |
| unsigned long daddr; |
| char useless; |
| unsigned char protocol; |
| unsigned short length; |
| }pseudo; |
| |
| struct sockaddr_in peer; |
| struct iphdr *ip; |
| |
| |
| ip = (struct iphdr *) malloc(sizeof(struct iphdr)); |
| udp = (struct udphdr *) malloc(sizeof(struct udphdr)); |
| packet = (char *) malloc(sizeof(struct iphdr) + |
| sizeof(struct udphdr) + 12); |
| buffer = (char *) malloc(sizeof(struct iphdr) + |
| sizeof(struct udphdr) + 12); |
| |
| |
| ip = (struct iphdr *) packet; |
| udp = (struct udphdr *) (packet + sizeof(struct iphdr)); |
| |
| |
| ip->ihl = 5; |
| ip->version = 4; |
| ip->tos = 0; |
| ip->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) +12; |
| ip->id = htons(getuid()); |
| ip->ttl = 255; |
| ip->protocol = IPPROTO_UDP; |
| ip->saddr = inet_addr("127.0.0.1"); |
| ip->daddr = inet_addr("127.0.0.1"); |
| |
| |
| sock = socket(AF_INET,SOCK_RAW,IPPROTO_UDP); |
| setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int)); |
| |
| pseudo.saddr = inet_addr("127.0.0.1"); |
| pseudo.daddr = inet_addr("127.0.0.1"); |
| pseudo.useless = htons(0); |
| pseudo.protocol = IPPROTO_UDP; |
| pseudo.length = sizeof(struct udphdr) + 12; |
| |
| |
| udp->source = htons(5000); |
| udp->dest = htons(7); |
| udp->len = htons(sizeof(struct udphdr) + 12); |
| udp->check = in_cksum((unsigned short *)&pseudo,sizeof(struct udphdr) |
| + sizeof(struct pseudohdr) + 12); |
| |
| ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr)); |
| |
| |
| strcpy((packet+sizeof(struct iphdr) + sizeof(struct udphdr)), |
| "Hello World"); |
| |
| peer.sin_family = AF_INET; |
| peer.sin_addr.s_addr = inet_addr("127.0.0.1"); |
| peer.sin_port = htons(7); |
| |
| sendto(sock,packet,ip->tot_len,0,(struct sockaddr *)&peer,sizeof |
| (struct sockaddr)); |
| |
| recv(sock,buffer,sizeof(struct iphdr)+sizeof(struct udphdr)+13,0); |
| |
| buffer += (sizeof(struct iphdr)+sizeof(struct udphdr)); |
| printf("Reply from Echo server:\t%s\n",buffer); |
| |
| close(sock); |
| return 0; |
| } |
| |
| [ Riferimenti ] |
| |
| |
| |
| Tcp/Ip Illustrated Volume 1 (The Protocol) |
| By W. Richard Stevens (Addison Wesley) |
| |
| Tcp/Ip Illustrated Volume 2 (The implementation) |
| By Gary R. Wright and W. Richard Stevens (Addition Wesley) |
| |
| Dai un'occhiata qui: |
| |
| http://www.exile2k.org Exile Team home page |
| http://www.hexedit.com HNS home page |
| http://www.eEyes.com eEyes home page |
| |
| |
| |
| [ Ringraziamenti ] |
| |
| |
| |
| Special thanx to: |
| My Exile team bro's: Mayhem(Tutu rose emulator), |
| Rix(Assembly wh0re), |
| Kraken(Saleter dhypee), |
| Ehoba(Pas toi!!!), |
| Liks(Erm...) |
| |
| or Europeen wh0res kinda synonyms =] |
| ---> keep it kool guys! |
| |
| #rhino9 peeps: Colonwq(Gotta learn you howto drink), |
| Hexedit(Lucky to be yourself), |
| Binf(Mon mentor de hacking y0), |
| Klog(Bleh j00), |
| zorkeres(Still sickshit addict?), |
| RcLocal(The french skill0rz), |
| and others |
| |
| People who supported me even if i was newbie: Utopiste, |
| Wyzeman... |
| |
| ~ My parents who made it possible during 1982's night... ~ |
| |
| God bless people i forget... |
| |
| |
| |
| |
| |
| Nitr0gen Exile Team 2000 Rock on! |
| nitr0gen@hackersnews.com |
| |
| |
| Tradotto da XpTerminator: |
| |
| spero proprio di aver tradotto bene... |
| per qualunque genere di errore segnalate a: |
| |
| xp_terminator@katamail.com |
| http://xpterminator.cjb.net |
| |
| Ciao a tutti! |
| |
| |
+--------------------------------------------------------------------------+