/* * This code is GPL. * See http://linux.die.net/man/3/libipq * Linux Day 2007, Giacomo Strangolino. * * To build, type: * gcc -o iptq iptq.c -lipq * Libraries and packages needed: * iptables-dev libnetfilter-queue-dev libnetfilter-queue1 * * kernel modules needed: * ip_queue / xt_NFQUEUE (if missing: Netlink Connection Refused) * iptable_filter * ip_tables * x_tables * * [Execute as root.] */ /* Si riporta di seguito la struttura ipq_packet_msg usata in questo programma. * Essa proviene da "ip_queue.h" in include/linux/netfilter_ipv4/ */ // /* Messages sent from kernel */ // typedef struct ipq_packet_msg { // unsigned long packet_id; /* ID of queued packet */ // unsigned long mark; /* Netfilter mark value */ // long timestamp_sec; /* Packet arrival time (seconds) */ // long timestamp_usec; /* Packet arrvial time (+useconds) */ // unsigned int hook; /* Netfilter hook we rode in on */ // char indev_name[IFNAMSIZ]; /* Name of incoming interface */ // char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */ // __be16 hw_protocol; /* Hardware protocol (network order) */ // unsigned short hw_type; /* Hardware type */ // unsigned char hw_addrlen; /* Hardware address length */ // unsigned char hw_addr[8]; /* Hardware address */ // size_t data_len; /* Length of packet data */ // unsigned char payload[0]; /* Optional packet data */ // } ipq_packet_msg_t; #include #include #include #include #include #include #include #include #include /* per inet_ntoa() */ #include #include #include /* per inet_ntoa() */ #include #include #define BUFSIZE 2048 #define RED "\e[1;31m" #define GREEN "\e[1;32m" #define VIOLET "\e[1;35m" #define YELLOW "\e[1;33m" #define CYAN "\e[1;36m" #define CLR "\e[0m" struct ipq_handle *h; /* Qui affinche' sia visibile dal signal_handler */ void signal_handler(int signo) { switch(signo) { case SIGINT: printf(VIOLET "\nInterrupt received.\n" CLR); ipq_destroy_handle(h); exit(EXIT_SUCCESS); case SIGTERM: printf(VIOLET "\nTERM received.\n" CLR); ipq_destroy_handle(h); exit(EXIT_SUCCESS); case SIGSEGV: printf(RED "\nSEGMENT VIOLATION received!\n" CLR); ipq_destroy_handle(h); exit(EXIT_FAILURE); } } static void exit_error(struct ipq_handle *h, const char *reason) { ipq_perror(reason); printf("exit_error(): Freeing handle\n"); ipq_destroy_handle(h); exit(1); } void print_ip_header(const unsigned char* buffer) { struct in_addr src, dst; /* cast del buffer a pacchetto IP: */ struct iphdr* ip_header = (struct iphdr* )buffer; /* ora posso accedere ai campi dell'IP: come esempio * stampero` l'indirizzo sorgente e destinazione. */ src.s_addr = ip_header->saddr; dst.s_addr = ip_header->daddr; char ips[32]; char ipd[32]; strncpy(ips , inet_ntoa(src) , 32); strncpy(ipd , inet_ntoa(dst) , 32); printf("IP: " CYAN "%s" CLR "->" GREEN "%s\t" CLR, ips, ipd); } /* Prints the source and destination ports from the TCP header. * Inoltre, stampa i FLAG TCP ATTIVI */ void print_tcp_header(const unsigned char *buf) { struct tcphdr* tcph = (struct tcphdr *) buf; printf("TCP: " CYAN "%d" CLR " -> " GREEN "%d" CLR, ntohs(tcph->source), ntohs(tcph->dest)); printf("\t"); if(tcph->syn) printf(GREEN "S" CLR "|"); if(tcph->ack) printf(YELLOW "A" CLR "|"); if(tcph->urg) printf("U|"); if(tcph->rst) printf(RED "R" CLR "|"); if(tcph->psh) printf("P|"); if(tcph->fin) printf(CYAN "F" CLR "|"); } int main(int argc, char **argv) { /* Una variabile atta a memorizzare lo stato delle chiamate */ int status; /* Politica da applicare ai pacchetti ricevuti dalla coda */ int policy; unsigned char buffer[BUFSIZE]; /* Leggo la linea di comando per la politica da applicare ai pacchetti */ if(argc != 2) { printf(RED "Uso: %s accept oppure drop\n" CLR, argv[0]); exit(EXIT_FAILURE); } if(strcmp(argv[1], "accept") == 0) policy = NF_ACCEPT; else if(strcmp(argv[1], "drop") == 0) policy = NF_DROP; else { printf(RED "Errore: parametro \"%s\" non valido\n" "Sono accettati solo i parametri \"accept\" e \"drop\"\n" CLR, argv[1]); exit(EXIT_FAILURE); } /* Installo gli handler dei segnali perche` all'uscita * vengano rimosse le strutture allocate per la coda. */ signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGSEGV, signal_handler); /* Creo uno `handle' per inizializzare libipq per la mia applicazione: * 0 sono i flags (per compatibilita` futura, ora non utilizzati; * PF_INET, indica IPv4. */ h = ipq_create_handle(0, PF_INET); /* Controllo il successo della ipq_create_handle() */ if (!h) exit_error(h, "ipq_create_handle(0, PF_INET)"); /* Chiedo al kernel di fornire assieme allo header anche i dati * del pacchetto di rete. * BUFSIZE specifica quanti byte copiare dal campo dati. Il massimo e` 65535. * ipq_set_mode() va usata subito dopo ipq_create_handle() per abilitare il * flusso dei pacchetti dal kernel verso questa applicazione in userspace. */ status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE); /* IPQ_COPY_META in alternativa */ if (status < 0) /* fallito ipq_set_mode() */ exit_error(h, "ipq_set_mode()"); do{ /* Leggo dalla coda finche` l'applicazione e` in esecuzione */ /* Il messaggio viene copiato dalla coda nella memoria puntata * da buffer, fino a BUFSIZE bytes. * h e` lo handle che deve essere preventivamente creato con successo. * ATTENZIONE: bisogna che `buffer' sia grande abbastanza per contenere il * messagggio, i.e. BUFSIZE! */ status = ipq_read(h, buffer, BUFSIZE, 0); if (status < 0) exit_error(h, "ipq_read()"); /* puntatore alla zona di memoria che conterra` il pacchetto*/ ipq_packet_msg_t *m; unsigned char *ip_header_pointer = NULL; unsigned char *tcp_header_pointer = NULL; struct iphdr* iph; switch (ipq_message_type(buffer)) /* che messaggio ho ricevuto dal kernel? */ { case NLMSG_ERROR: /* un errore dal framework `Netlink' */ fprintf(stderr, "Received error message %d\n", ipq_get_msgerr(buffer)); break; case IPQM_PACKET: /* un pacchetto IP e` stato correttamente recapitato, metadati + payload (opzionale) */ /* dal buffer ricavo le informazioni del pacchetto in coda */ m = ipq_get_packet(buffer); if(m->indev_name[0]) { printf(VIOLET "IN " CLR); printf("[%s] ", m->indev_name); } else if(m->outdev_name[0]) { printf(YELLOW "OUT " CLR); printf("[%s] ", m->outdev_name); } /* stampo l'header IP, se la lunghezza del campo `data` * e` lunga abbastanza da contenerlo: */ if (m->data_len >= sizeof(struct iphdr)) { /* il puntatore ai dati deve essere posizionato * all'inizio dello header IP, ovvero a una distanza * di byte pari alla grandezza della struttura * `ipq_packet_msg_t' a partire dal puntatore base * `m' */ ip_header_pointer = m->payload; print_ip_header(ip_header_pointer); iph = (struct iphdr*) ip_header_pointer; /* Vediamo se c'e'' spazio per l'header TCP: */ switch(iph->protocol) { case IPPROTO_TCP: if (m->data_len >= 4 * iph->ihl + sizeof(struct tcphdr)) { /* Ricaviamo il puntatore all'header TCP: */ tcp_header_pointer = m->payload + iph->ihl * 4; print_tcp_header(tcp_header_pointer); } else printf(" NOT ENOUGH SPACE FOR TCP HEADER!"); break; case IPPROTO_UDP: printf(RED "PROTOCOLLO UDP NON SUPPORTATO" CLR); break; default: printf(RED "PROTOCOLLO %d NON SUPPORTATO" CLR, iph->protocol); break; } } /* Alla fine decido il verdetto per il pacchetto: * in questo caso NF_ACCEPT, ovvero lo accetto. * Il quarto parametro rappresenta la lunghezza dei dati * puntati dal quinto parametro (unsigned char* buffer) * una versione opzionale del campo dati modificata. */ status = ipq_set_verdict(h, m->packet_id, policy, 0, NULL); if (status < 0) exit_error(h, "ipq_read()"); /* Stampo infine l'esito del verdetto, che dipende dal parametro * passato da linea di comando. */ if(policy == NF_DROP) printf("\t[" RED "BLOCCATO" CLR "]\n"); else printf("\t[" GREEN "OK" CLR "]\n"); break; default: fprintf(stderr, "Unknown message type!\n"); break; } } while (1); return 0; }