PDA

Visualizza la versione completa : [C] Programmazione di rete: creazione di uno sniffer


erbedo
18-10-2006, 19:48
Ciao a tutti, sto cercando di realizzare un'applicazione che resti in ascolto sulla rete e stampi tutto quello che passa, uno sniffer insomma.
I pacchetti vengono presi da iptables.
Attualmente riesco solo a stampare alcune cose ma non altre che mi interesserebbero di piu. Posto il codice:
/*
* This code is GPL.
*/
#include <linux/netfilter.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <libipq.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE 2048

static void die (struct ipq_handle *h) {
ipq_perror ("there was an error");
ipq_destroy_handle (h);
exit (1);
}

int main (int argc, char **argv) {
int status;
unsigned char buf[BUFSIZE];
struct ipq_handle *h;

/* Creating an handle */
h = ipq_create_handle (0, PF_INET);
if (!h)
die (h);

/* Copying all the packet and not only metadata */
status = ipq_set_mode (h, IPQ_COPY_PACKET, BUFSIZE);
if (status < 0)
die (h);

do {
status = ipq_read (h, buf, BUFSIZE, 0);
if (status < 0)
die (h);

switch (ipq_message_type (buf)) {

case NLMSG_ERROR: {
fprintf (stderr, "Received error message %d\n",
ipq_get_msgerr (buf));
break;
}

case IPQM_PACKET: {
ipq_packet_msg_t *m = ipq_get_packet (buf);

struct iphdr *ip = (struct iphdr *) m->payload;

//struct in_addr s_addr = ip->ip_src;
//struct in_addr d_addr = ip->ip_dst;
u_int32_t src_addr = ntohl(ip->saddr);

fprintf(stderr, "Source address = %d", src_addr);

struct tcphdr *tcp = (struct tcphdr *) (m->payload + (4 * ip->ihl));
int src_port = ntohs (tcp->source);
int dest_port = ntohs (tcp->dest);

fprintf (stderr, "\nReceived a packet!!!\n");
fprintf (stderr, "Source port = %d - ", src_port);
fprintf (stderr, "Destination port = %d\n", dest_port);
fprintf (stderr, "Syn = %d - ", tcp->syn);
fprintf (stderr, "RST = %d - ", tcp->rst);
fprintf (stderr, "Fyn = %d - ", tcp->fin);
fprintf (stderr, "Ack = %d\n", tcp->ack);
fprintf (stderr, "Sequence = %d\n", ntohs (tcp->seq));
/*fprintf(stderr, "Packet ID = %d\n", m->packet_id);
* fprintf(stderr, "Marked = %d\n", m->mark);
* fprintf(stderr, "Hook = %d\n", m->hook);
* fprintf(stderr, "Data Len = %d\n", m->data_len);
* fprintf(stderr, "Payload = %c\n", m->payload[sizeof(m->payload)]);
* fprintf(stderr, "From = %s\n", m->hw_addr[sizeof(m->hw_addr)]);
* fprintf(stderr, "Buffer = %c\n", buf); */

status = ipq_set_verdict (h, m->packet_id, NF_ACCEPT,
0, NULL);
if (status < 0)
die (h);
break;
}

default: {
fprintf (stderr, "Unknown message type!\n");
break;
}
}
}
while (1);

ipq_destroy_handle (h);
return 0;
}

Ad esempio, mi piacerebbe sapere se un pacchetto sta entrando nella mia rete o sta cercando di uscire. Inoltre, cosa molto importante, l'indirizzo IP sorgente e destinazione. Quando lo provo a stampare ottengo solo sequenze di numeri, e non indirizzi. Credo che bisognera convertirlo, ma non conosco nessuna primitiva che lo permetta...
Qualche aiuto? Grazie :)

erbedo
22-10-2006, 16:42
Nessuno ha qualche idea?

Habanero
23-10-2006, 13:54
gli ip prima di stamparli devi convertirli in ascii... usa inet_ntoa()

char* inet_ntoa(struct in_addr ip);

Per sapere se è un pacchetto entra o esce basta conoscere il proprio IP e confrontarlo con l'indirizzo sorgente e destinazione del pacchetto che ti è arrivato...

erbedo
23-10-2006, 14:18
Si ho provato, pero non capisco come ottenere una struttura sockaddr_in. Cioe, una volta ottenuto l'iphdr e il tcphdr, come faccio per separare la struttura sockaddr_in e quindi poi usare giustamente la inet_ntoa come mi hai detto?

Grazie Ciao

Habanero
23-10-2006, 14:34
nella struct iphdr i campi ip_src e ip_dst sono già delle struct in_addr
sockaddr_in non c'entra nulla direi...

Nel tuo caso dovrebbe bastare un :

printf("IP sorgente: %s\n", inet_ntoa(ip->ip_src));
printf("IP destinazione: %s\n", inet_ntoa(ip->ip_dst));

erbedo
23-10-2006, 20:26
Pero la struttura iphdr non ha un campo ip_src. Questo e' il risukltato della compilazione:
bedo@harry:~/Projects/Reti/src$ gcc main.c -o prova -lipq
main.c: In function ‘main’:
main.c:56: error: ‘struct iphdr’ has no member named ‘ip_src’
bedo@harry:~/Projects/Reti/src$
Credo di dover usare saddr come campo, ma se lo uso di fatto il risultato che ottengo e'
IP = -1208849356
che direi che e' errato -_- :)

Ho provato anche a convertirlo da rete a host con ntohs o ntohl, ma il risultato non cambia, ottengo valori strampalati del tipo
IP = 1460082805
IP = -1208849356

Douh!

zero85
23-10-2006, 20:37
http://www.nersc.gov/~scottc/misc/docs/snort-2.1.1-RC1/packet__types_8h-source.html
riga 00148, sono membri di tipo struct in_addr.

Habanero
23-10-2006, 21:05
Originariamente inviato da zero85
http://www.nersc.gov/~scottc/misc/docs/snort-2.1.1-RC1/packet__types_8h-source.html
riga 00148, sono membri di tipo struct in_addr.

è esattamente la pagina da dove ho ricavato la struttura...
nella riga 160 sono definiti ip_src e ip_dst....
l'header ip non può non avere un campo sorgente....

ntohs o ntohl non c'entrano proprio nulla.

Habanero
23-10-2006, 21:16
aspetta.... forse la struttura è questa che ha nomi un filo diversi...
http://www.valtellinux.it/knights/programmazione-2.html

verifica se corrisponde al tuo ip.h

se così è gli indirizzi sorgente e destinazione sono saddr e daddr ma vengono definiti come u_int32 (unsigned long) e non come struttura in_addr (anche se alla fine sono entrambi unsigned long)

prova così:


printf("IP sorgente: %s\n", inet_ntoa((struct in_addr)ip->saddr));
printf("IP destinazione: %s\n", inet_ntoa((struct in_addr)ip->daddr));

erbedo
23-10-2006, 23:04
Allora, come mi hai detto tu non funziona, ma mettendo che sono puntatori a dei in_addr funziona tutto e viene stampato correttamente l'IP :)
Questo e' esattamente cio che volevo ottenere, ed e' un notevole passo avanti sul mio lavoro.
Ora mi piacerebbe capire il perche, ovvero: essendo entrambi degli unsigned long, come mai facendo il cast funziona?

Loading