1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
/* * Sniffer base * by Gnix <gnixmail@gmail.com> * http://gnix.netsons.org */ #include <stdio.h> // Standard I/O #include <stdlib.h> // Standard Library #include <string.h> // String functions #include <unistd.h> // Standard Unix #include <errno.h> // Gestione errori #include <net/if.h> // Contiene la struttura ifreq e la costante simbolica IF_NAMESIZE #include <sys/ioctl.h> // ioctl #include <sys/socket.h> // Socket functions #include <linux/if_packet.h> // Contiene la struttura sockaddr_ll #include <linux/if_ether.h> // Contiene la costante simbolica ETH_P_IP #include <linux/ip.h> // Contiene la struttura iphdr #include <linux/tcp.h> // Contiene la struttura tcphdr #include <linux/udp.h> // Contiene la struttura udphdr #include <netinet/in.h> // Contiene la costante simbolica IPPROTO_TCP #define STAT(x) ((x)) ? 1 : 0 #define BUFFER_SIZE 2048 // Crea un raw socket int raw_socket(int protocol) { int rawsock; if((rawsock = socket(PF_PACKET, SOCK_RAW, htons(protocol)))== -1) { perror("Error creating raw socket: "); exit(-1); } return rawsock; } // Collega il raw socket a una data interfaccia. L'interfaccia e' gestita // come un semplice numero dal Kernel. Questo numero viene ricavato con la // chiamata a ioctl. int raw_bind(char *device, int rawsock, int protocol) { struct sockaddr_ll sll; struct ifreq ifr; bzero(&sll, sizeof(sll)); bzero(&ifr, sizeof(ifr)); // Ricava l'interface index strncpy((char *)ifr.ifr_name, device, IFNAMSIZ); if((ioctl(rawsock, SIOCGIFINDEX, &ifr)) == -1) { printf("Error getting Interface index !\n"); exit(-1); } // Popola struttura sll e fai bind sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_protocol = htons(protocol); if((bind(rawsock, (struct sockaddr *)&sll, sizeof(sll)))== -1) { perror("Error binding raw socket to interface\n"); exit(-1); } return 0; } // Stampa in esadecimale void printHex(char *mesg, unsigned char *p, int len) { printf("%s", mesg); while(len--) { printf("%.2X ", *p); p++; } printf("\n"); } // Stampa il pachetto void printPacket(unsigned char *packet, int len) { // Variabili struct ethhdr *ethernet_header; struct iphdr *ip_header; struct tcphdr *tcp_header; struct udphdr *udp_header; unsigned char *data; int data_len = 0; // Stampa messaggio iniziale printf("\n\n################[ Packet Starts ]################"); // Controlla che la dimensione del pacchetto sia maggiore degli header ethernet e ip sommati. if(len >= (sizeof(struct ethhdr) + sizeof(struct iphdr))) { // Casting in ethhdr ethernet_header = (struct ethhdr*)packet; // Stampa header ethernet printf("\n----- Ethernet Header -----\n"); printHex("ETH: Dest MAC : ", ethernet_header->h_dest, 6); printHex("ETH: Source MAC : ", ethernet_header->h_source, 6); printHex("ETH: Protocol : ", (void*)ðernet_header->h_proto, 2); // Controlla che il protocollo sia IP if(ntohs(ethernet_header->h_proto) == ETH_P_IP) { // Casting in iphdr ip_header = (struct iphdr*)(packet + sizeof(struct ethhdr)); printf("\n----- IP Header -----\n"); printf("IP: Header length : %d bytes\n", ip_header->ihl*4); printf("IP: Version : %d \n", ip_header->version); printf("IP: Type of Service : %d \n", ip_header->tos); printf("IP: Total length : %d \n", ntohs(ip_header->tot_len)); printf("IP: Identification : %d \n", ntohs(ip_header->id)); printf("IP: Flags : %.2x\n", (unsigned char)((ip_header->frag_off)>>12)); printf("IP: Fragment offset : %d \n", ntohs(ip_header->frag_off) & 0x0FFF); printf("IP: Time to live : %d \n", ip_header->ttl); printf("IP: Protocol : %d \n", ip_header->protocol); printf("IP: Header checksum : %d \n", ntohs(ip_header->check)); printf("IP: Source IP Address: %s \n", inet_ntoa(ip_header->saddr)); printf("IP: Dest IP Address : %s \n", inet_ntoa(ip_header->daddr)); // Controlla che il protocollo sia tcp e che la dimensione del pacchetto sia almeno la somma di header eth,ip e tcp if((ip_header->protocol == IPPROTO_TCP) && (len >= (sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr)))) { // Casting in tcphdr tcp_header = (struct tcphdr*)(packet + sizeof(struct ethhdr) + ip_header->ihl*4); printf("\n----- TCP Header -----\n"); printf("TCP: Source port : %d\n", ntohs(tcp_header->source)); printf("TCP: Dest port : %d\n", ntohs(tcp_header->dest)); printf("TCP: Sequence number : %u\n", ntohl(tcp_header->seq)); printf("TCP: Acknowledgment number: %u\n", ntohl(tcp_header->ack_seq)); printf("TCP: Reserved : %d\n", tcp_header->res1); printf("TCP: Data offset : %d\n", tcp_header->doff*4); printf("TCP: Flags\n"); printf("TCP: FIN : %d\n", STAT(tcp_header->fin)); printf("TCP: SYN : %d\n", STAT(tcp_header->syn)); printf("TCP: RST : %d\n", STAT(tcp_header->rst)); printf("TCP: PSH : %d\n", STAT(tcp_header->psh)); printf("TCP: ACK : %d\n", STAT(tcp_header->ack)); printf("TCP: URG : %d\n", STAT(tcp_header->urg)); printf("TCP: ECE : %d\n", STAT(tcp_header->ece)); printf("TCP: CWR : %d\n", STAT(tcp_header->cwr)); printf("TCP: Window : %d\n", ntohs(tcp_header->window)); printf("TCP: Checksum : %d\n", ntohs(tcp_header->check)); // Ricava posizione dei dati e stampa data = (packet + sizeof(struct ethhdr) + ip_header->ihl*4 + sizeof(struct tcphdr)); data_len = ntohs(ip_header->tot_len) - ip_header->ihl*4 - sizeof(struct tcphdr); printHex("DATA: ", data, data_len); } // Controlla che il protocollo sia udp e che la dimensione del pacchetto sia almeno la somma di header eth, ip e udp else if((ip_header->protocol == IPPROTO_UDP) && (len >= (sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr)))) { // Casting in udphdr udp_header = (struct udphdr*)(packet + sizeof(struct ethhdr) + ip_header->ihl*4); printf("\n----- UDP Header -----\n"); printf("UDP: Source port: %d\n", htons(udp_header->source)); printf("UDP: Dest port : %d\n", htons(udp_header->dest)); printf("UDP: Length : %d\n", htons(udp_header->len)); printf("UDP: Checksum : %d\n", htons(udp_header->check)); // Ricava posizione dei dati e stampa data = (packet + sizeof(struct ethhdr) + ip_header->ihl*4 + sizeof(struct udphdr)); data_len = ntohs(ip_header->tot_len) - ip_header->ihl*4 - sizeof(struct udphdr); printHex("DATA: ", data, data_len); } else { printf("Not a TCP or UDP packet.\n"); } } } else { printf("Packet size too small!\n"); } // Stampa messaggio finale printf("################[ Packet Ends ]################\n\n"); } // Programma principale int main(int argc, char **argv) { // Variabili int raw; // raw socket descriptor unsigned char buffer[BUFFER_SIZE]; // buffer per i dati int len; // lunghezza buffer di dati ricevuto int n_packets; // numero pacchetti da sniffare struct sockaddr_ll info; // struttura utilizzata in recvfrom int info_size = sizeof(info); // dimensione struttura sockaddr_ll // crea raw socket raw = raw_socket(ETH_P_IP); // Bind socket all'interface raw_bind(argv[1], raw, ETH_P_IP); // Numero pacchetti da sniffare n_packets = atoi(argv[2]); // Inizia sniffing while(n_packets--) { if((len = recvfrom(raw, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&info, &info_size)) == -1) { perror("Recv from returned -1: "); exit(-1); } else { // Pacchetto ricevuto. printPacket(buffer, len); } } return 0; }
Refactorings
No refactoring yet !
An example of sniffer that use raw socket. Comments are in italian.