/* * This is the rtapanalyser library, Wi-Fi packet sniffer and analyser, * thanks to the radiotap header of each packet. */ #include "rtapscanmob.h" BOOL run = TRUE ; /* Capture des paquets en utilisant l'interface "capture_iface" pendant "capture_time" millisecondes, * et enregistre les paquets lus dans "results" */ int capture(char *capture_iface, unsigned long capture_time, mac_list **results, BOOL print_values) { pcap_t *handle ; // Descripteur de capture de paquets char errbuf[PCAP_ERRBUF_SIZE] ; // Message d'erreur struct timeval tbegin, tcurrent ; /* Sous-fonction de traitement des paquets capturés */ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { read_packet(args, header, packet, results, print_values) ; // On appelle la fonction read_packet() avec les mêmes arguments, plus "results" que l'on passe en modification, et "print_values" qui indique si on doit afficher le paquet. } handle = pcap_open_live(capture_iface, BUFSIZ, 1, 1000, errbuf) ; // Début de la capture if (handle == NULL) // Le lancement de la capture a-t-il échoué ? { fprintf(stderr, "Impossible d'ouvrir l'interface « %s » : %s\n", capture_iface, errbuf) ; return ERR_OPENING_IFACE ; } if (capture_time > 0) // Si le temps de capture est positif { gettimeofday(&tbegin, NULL) ; // Récupère l'heure courante (heure du lancement de la capture) while (run) { pcap_loop(handle, 1, got_packet, NULL) ; // Collecte 1 paquet et appelle la fonction got_packet quand pcaploop a recupéré des paquets gettimeofday(&tcurrent, NULL) ; // Récupère l'heure courante if(sub_date(tcurrent, tbegin) > capture_time) // Si le temps de capture est écoulé break ; // on arrête la collecte. } } else // On fonctionne en mode démon (tant que run est vrai) while (run) pcap_loop(handle, 1, got_packet, NULL) ; // Collecte 1 paquet et appelle la fonction got_packet quand pcaploop a recupéré des paquets pcap_close(handle) ; // Arrêt de la capture. return 0 ; } /* Traite un paquet et enregistre les valeurs dans la liste des résultats (results) */ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, mac_list **results, BOOL print_values) { unsigned char *data = (unsigned char *) packet ; // Recopie dans data l'adresse du paquet capturé unsigned short rtap_bytes ; // Taille des données reçues unsigned int rtap_presentflags, rtap_position ; BOOL check[15] ; // Champs présents unsigned char raw_packet_type ; // Type du packet reçu (beacon, data...) unsigned char mac_addr_bytes[6] ; mac_list *tmp_mac = NULL ; ss_list *tmp_ss = NULL ; int i ; // Compteur memcpy(&rtap_bytes, &data[2], sizeof(unsigned short)) ; // Recopie les deux octets à partir du troisième octet de donnée qui est la taille de l'en-tête rtap (change avec des flags) raw_packet_type = data[rtap_bytes] ; // Au bout de l'en-tête rtap il y a celle du 802.11 dont le premier determine le type (beacon ou pas) if (raw_packet_type == RAW_PACKET_TYPE_BEACON) // Si le paquet est de type beacon, on le traite { memcpy(mac_addr_bytes, &data[rtap_bytes+10], 6); // Dans le cas du beacon, l'adresse MAC est 10 octets plus loin que le type de paquet memcpy(&rtap_presentflags, &data[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS); // Récupère les flags de l'en-tête rtap /* Ajout du résultat du scan à la structure */ tmp_ss = malloc(sizeof(ss_list)) ; tmp_ss->next = NULL ; memcpy(&(tmp_ss->header_revision), &data[RTAP_P_HREVISION], RTAP_L_HREVISION) ; memcpy(&(tmp_ss->header_pad), &data[RTAP_P_HPAD], RTAP_L_HPAD) ; memcpy(&(tmp_ss->header_length), &data[RTAP_P_HLENGTH], RTAP_L_HLENGTH) ; memcpy(&(tmp_ss->present_flags), &data[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS) ; for(i = 0 ; i < 15 ; i++) // Initialisation de la structure des champs présents tmp_ss->check[i] = FALSE ; rtap_position = 8 ; // début des champs déterminés par le present flag if (print_values) { char *mac_string = mac_bytes_to_string(mac_addr_bytes) ; printf("[%s]\n", mac_string) ; printf("Header revision : %hhu\n", tmp_ss->header_revision) ; printf("Header Pad : %hhu\n", tmp_ss->header_pad) ; printf("Header Length : %hu\n", tmp_ss->header_length) ; printf("Present flags : %#010lx\n", tmp_ss->present_flags) ; free(mac_string) ; } for(i=0 ; i < 15 ; i++) // on teste les 15 premiers bits du champ flag afin de valider la présence et de les copier { if((rtap_presentflags % 2) == 1) { switch(i) { case RTAP_MACTS: memcpy(&(tmp_ss->mac_timestamp), &data[rtap_position], RTAP_L_MACTS) ; tmp_ss->check[RTAP_MACTS] = TRUE ; if (print_values) printf("Mac timestamp : %llu\n", tmp_ss->mac_timestamp) ; rtap_position += RTAP_L_MACTS ; break ; case RTAP_FLAGS: memcpy(&(tmp_ss->flags), &data[rtap_position], RTAP_L_FLAGS) ; tmp_ss->check[RTAP_FLAGS] = TRUE; if (print_values) printf("Flags : %hu\n", tmp_ss->flags); rtap_position += RTAP_L_FLAGS ; break ; case RTAP_RATE: memcpy(&(tmp_ss->data_rate), &data[rtap_position], RTAP_L_RATE) ; tmp_ss->check[RTAP_RATE] = TRUE; if (print_values) printf("Data rate : %hhd MB/s\n", tmp_ss->data_rate / 2) ; rtap_position += RTAP_L_RATE ; break ; case RTAP_CHANNEL: memcpy(&(tmp_ss->channel), &data[rtap_position], RTAP_L_CHANNEL) ; rtap_position += RTAP_L_CHANNEL ; tmp_ss->check[RTAP_CHANNEL] = TRUE; memcpy(&(tmp_ss->channel_type), &data[rtap_position], RTAP_L_CHANNELTYPE) ; if (print_values) printf("Channel : %hu MHz\nChannel Type : %#06x\n", tmp_ss->channel, tmp_ss->channel_type); rtap_position += RTAP_L_CHANNELTYPE ; break ; case RTAP_FHSS: memcpy(&(tmp_ss->fhss), &data[rtap_position], RTAP_L_FHSS) ; tmp_ss->check[RTAP_FHSS] = TRUE; if (print_values) printf("FHSS : %hu\n", tmp_ss->fhss); rtap_position += RTAP_L_FHSS ; break ; case RTAP_ANTENNASIGNALDBM: memcpy(&(tmp_ss->antenna_signal_dbm), &data[rtap_position], RTAP_L_ANTENNASIGNALDBM) ; tmp_ss->check[RTAP_ANTENNASIGNALDBM] = TRUE; if (print_values) printf("Antenna Signal : %d dBm\n", tmp_ss->antenna_signal_dbm - 0x100); rtap_position += RTAP_L_ANTENNASIGNALDBM ; break ; case RTAP_ANTENNANOISEDBM: memcpy(&(tmp_ss->antenna_noise_dbm), &data[rtap_position], RTAP_L_ANTENNANOISEDBM) ; tmp_ss->check[RTAP_ANTENNANOISEDBM] = TRUE; if (print_values) printf("Antenna Noise : %d dBm\n", tmp_ss->antenna_noise_dbm - 0x100); rtap_position += RTAP_L_ANTENNANOISEDBM ; break ; case RTAP_LOCKQUALITY: memcpy(&(tmp_ss->lock_quality), &data[rtap_position], RTAP_L_LOCKQUALITY) ; tmp_ss->check[RTAP_LOCKQUALITY] = TRUE; if (print_values) printf("Lock Quality : %hu\n", tmp_ss->lock_quality); rtap_position += RTAP_L_LOCKQUALITY ; break ; case RTAP_TXATTENUATION: memcpy(&(tmp_ss->tx_attenuation), &data[rtap_position], RTAP_L_TXATTENUATION) ; tmp_ss->check[RTAP_TXATTENUATION] = TRUE; if (print_values) printf("Taux Attenuation : %hu\n", tmp_ss->tx_attenuation); rtap_position += RTAP_L_TXATTENUATION ; break ; case RTAP_TXATTENUATIONDB: memcpy(&(tmp_ss->tx_attenuation_db), &data[rtap_position], RTAP_L_TXATTENUATIONDB) ; tmp_ss->check[RTAP_TXATTENUATIONDB] = TRUE; if (print_values) printf("Atténuation : %hu dB\n", tmp_ss->tx_attenuation_db); rtap_position += RTAP_L_TXATTENUATIONDB ; break ; case RTAP_TXATTENUATIONDBM: memcpy(&(tmp_ss->tx_attenuation_dbm), &data[rtap_position], RTAP_L_TXATTENUATIONDBM) ; tmp_ss->check[RTAP_TXATTENUATIONDBM] = TRUE; if (print_values) printf("Atténuation : %hu dBm\n", tmp_ss->tx_attenuation_dbm); rtap_position += RTAP_L_TXATTENUATIONDBM ; break ; case RTAP_ANTENNA: memcpy(&(tmp_ss->antenna), &data[rtap_position], RTAP_L_ANTENNA) ; tmp_ss->check[RTAP_ANTENNA] = TRUE; if (print_values) printf("Antenna : %hhu\n", tmp_ss->antenna); rtap_position += RTAP_L_ANTENNA ; break ; case RTAP_ANTENNASIGNALDB: memcpy(&(tmp_ss->antenna_signal_db), &data[rtap_position], RTAP_L_ANTENNASIGNALDB) ; tmp_ss->check[RTAP_ANTENNASIGNALDB] = TRUE; if (print_values) printf("Antenna Signal : %hhu dB\n", tmp_ss->antenna_signal_db); rtap_position += RTAP_L_ANTENNASIGNALDB ; break ; case RTAP_ANTENNANOISEDB: memcpy(&(tmp_ss->antenna_noise_db), &data[rtap_position], RTAP_L_ANTENNANOISEDB) ; tmp_ss->check[RTAP_ANTENNANOISEDB] = TRUE; if (print_values) printf("Antenna Noise : %hhu dB\n", tmp_ss->antenna_noise_db); rtap_position += RTAP_L_ANTENNANOISEDB ; break ; case RTAP_FCS: memcpy(&(tmp_ss->fcs), &data[rtap_position], RTAP_L_FCS) ; tmp_ss->check[RTAP_FCS] = TRUE; if (print_values) printf("FCS : %lu\n", tmp_ss->fcs) ; rtap_position += RTAP_L_FCS ; break ; } } rtap_presentflags /= 2 ; } if (print_values) printf("\n") ; tmp_mac = *results ; if(*results == NULL) // Si la liste de résultats n'existe pas encore, { tmp_mac = malloc(sizeof(mac_list)) ; // on la crée. memcpy(tmp_mac->mac_addr_bytes, mac_addr_bytes, 6) ; tmp_mac->nb_samples = 1 ; tmp_mac->next = NULL ; tmp_mac->samples_list = tmp_ss ; *results = tmp_mac ; } else { while(tmp_mac != NULL) { if(mac_cmp(mac_addr_bytes, tmp_mac->mac_addr_bytes) == 1) break ; tmp_mac = tmp_mac->next ; } if(tmp_mac == NULL) { tmp_mac = malloc(sizeof(mac_list)) ; memcpy(tmp_mac->mac_addr_bytes, mac_addr_bytes, 6) ; tmp_mac->nb_samples = 1 ; tmp_mac->next = *results ; tmp_mac->samples_list = tmp_ss ; *results = tmp_mac ; } else { tmp_mac->nb_samples++ ; tmp_ss->next = tmp_mac->samples_list ; tmp_mac->samples_list = tmp_ss ; } } } } /* Affiche la liste chaînée des résultats */ void print_mac_list(mac_list *results, BOOL verbose) { mac_list *mac_ptr = results ; // Récupère la liste d'adresse MAC en entrée ss_list *ss_ptr = NULL ; // Initialise la sous-liste char *mac_string ; double antenna_signal_average = 0 ; // Moyenne des valeurs récupérées de antenna signal en dBm double antenna_noise_average = 0; // Moyenne des valeurs récupérées de antenna noise en dBm double data_rate_average = 0; // Moyenne du débit unsigned short channel = -1 ; // Canal utilisé pour la MAC courante unsigned short channel_type = -1 ; // Type de liaison utilisée pour la MAC courante if (results == NULL) // Si la liste est vide { printf("Aucun résultat.\n") ; // on l'affiche. return ; } while (mac_ptr != NULL) { mac_string = mac_bytes_to_string(mac_ptr->mac_addr_bytes) ; ss_ptr = mac_ptr->samples_list ; // On récupère le pointeur de la sous-liste antenna_signal_average = 0 ; antenna_noise_average = 0 ; data_rate_average = 0 ; while (ss_ptr != NULL) // On parcourt toutes les valeurs de l'affaiblissement en dB et on en fait la moyenne. { antenna_signal_average += pow((double)10, ((double)(ss_ptr->antenna_signal_dbm - 0x100) / 10)) ; // Il faut le minorer de 256 pour avoir la vrai puissance car sinon codage serai sur plus d'un octet. antenna_noise_average += pow((double)10, ((double)(ss_ptr->antenna_noise_dbm - 0x100) / 10)) ; data_rate_average += ((ss_ptr->data_rate) / 2); channel = ss_ptr->channel ; channel_type = ss_ptr->channel_type ; if (verbose) // Affichage du maillon si on est en mode verbeux. { printf("[%s]\n", mac_string) ; print_ss_list(ss_ptr) ; putchar('\n') ; } ss_ptr = ss_ptr->next ; } /* Calcul des moyennes */ antenna_signal_average = 10 * log10((double)(antenna_signal_average / mac_ptr->nb_samples)) ; antenna_noise_average = 10 * log10((double)(antenna_noise_average / mac_ptr->nb_samples)) ; data_rate_average /= (double)mac_ptr->nb_samples ; /* Affichage */ printf("[%s] [Canal : %hhd] [Fréquence : %hu MHz] [Type de liaison : %#06x] [Moyenne du débit : %0.1f Mo/s] [Moyenne du signal : %0.1f dBm] [Moyenne du bruit : %0.1f dBm]\n", mac_string, frequency_to_channel(channel), channel, channel_type, data_rate_average, antenna_signal_average, antenna_noise_average) ; if (verbose) printf("\n\n") ; free(mac_string) ; mac_ptr = mac_ptr->next ; } } /* Affiche un maillon d'une sous-liste de résultats */ void print_ss_list(ss_list *ss) { if (ss == NULL) return ; /* Champs statiques */ printf("Header revision : %hhu\n", ss->header_revision) ; printf("Header Pad : %hhu\n", ss->header_pad) ; printf("Header Length : %hu\n", ss->header_length) ; printf("Present flags : %#010lx\n", ss->present_flags) ; // Largeur de champ 10 : 2 pour "0x" et 8 pour la valeur. /* Champs dynamiques */ if (ss->check[RTAP_MACTS]) printf("Mac timestamp : %llu\n", ss->mac_timestamp) ; if (ss->check[RTAP_FLAGS]) printf("Flags : %hu\n", ss->flags) ; if (ss->check[RTAP_RATE]) printf("Data rate : %hhd MB/s\n", ss->data_rate / 2) ; if (ss->check[RTAP_CHANNEL]) printf("Channel : %hu MHz\nChannel Type : %#06x\n", ss->channel, ss->channel_type) ; if (ss->check[RTAP_FHSS]) printf("FHSS : %hu\n", ss->fhss) ; if (ss->check[RTAP_ANTENNASIGNALDBM]) printf("Antenna Signal : %d dBm\n", ss->antenna_signal_dbm - 0x100) ; if (ss->check[RTAP_ANTENNANOISEDBM]) printf("Antenna Noise : %d dBm\n", ss->antenna_noise_dbm - 0x100) ; if (ss->check[RTAP_LOCKQUALITY]) printf("Lock Quality : %hu\n", ss->lock_quality) ; if (ss->check[RTAP_TXATTENUATION]) printf("Taux Attenuation : %hu\n", ss->tx_attenuation) ; if (ss->check[RTAP_TXATTENUATIONDB]) printf("Atténuation : %hu dB\n", ss->tx_attenuation_db) ; if (ss->check[RTAP_TXATTENUATIONDBM]) printf("Atténuation : %hu dBm\n", ss->tx_attenuation_dbm) ; if (ss->check[RTAP_ANTENNA]) printf("Antenna : %hhu\n", ss->antenna) ; if (ss->check[RTAP_ANTENNASIGNALDB]) printf("Antenna Signal : %hhu dB\n", ss->antenna_signal_db) ; if (ss->check[RTAP_ANTENNANOISEDB]) printf("Antenna Noise : %hhu dB\n", ss->antenna_noise_db) ; if (ss->check[RTAP_FCS]) printf("FCS : %lu\n", ss->fcs) ; } /* Vide la liste chaînée d'adresse MAC */ void free_mac_list(mac_list **results) { mac_list *mac_ptr = *results ; ss_list *ss_ptr = NULL ; if (*results != NULL) { while(mac_ptr != NULL) { ss_ptr = mac_ptr->samples_list ; while (ss_ptr != NULL) { ss_ptr = ss_ptr->next ; free(mac_ptr->samples_list) ; mac_ptr->samples_list = ss_ptr ; } mac_ptr = mac_ptr->next ; free(*results) ; *results = mac_ptr ; } } } /* Enregistre la liste "results" dans le fichier "file" */ int write_mac_list_to_file(char *file, mac_list *results) { int fd = 0 ; // Descripteur de fichier. mac_list *ptr ; // Tête de lecture de la liste chaînée. ss_list *ss_ptr ; // Tête de lecture de la sous-liste. int mac_list_size = sizeof(mac_list) ; int ss_list_size = sizeof(ss_list) ; /* Ouverture du fichier */ fd = open(file, O_WRONLY | O_CREAT) ; if (fd < 0) { perror("Impossible d'ouvrir le fichier de sortie ") ; return ERR_OPENING_FILE ; } /* Écriture des données */ ptr = results ; // On commence par la tête de la liste (forcément...). while (ptr != NULL) { /* Enregistrement du maillon de la liste principale */ if (write(fd, ptr, mac_list_size) != mac_list_size) perror("Erreur d'écriture (mac_list) ") ; /* Enregistrement de la sous-liste */ ss_ptr = ptr->samples_list ; while (ss_ptr != NULL) { if (write(fd, ss_ptr, ss_list_size) != ss_list_size) // Écriture du maillon courant. perror("Erreur d'écriture (ss_list) ") ; ss_ptr = ss_ptr->next ; } ptr = ptr->next ; } /* Fermeture du fichier */ if (close(fd) != 0) perror("Erreur lors de la fermeture du fichier de sortie ") ; return 0 ; } /* Lit le fichier "file" et enregistre la liste lue dans "results" */ int read_mac_list_from_file(char *file, mac_list **results) { int fd = 0 ; // Descripteur de fichier. mac_list *ptr = NULL ; // Tête de lecture de la liste chaînée. ss_list *ss_ptr ; // Tête de lecture de la sous-liste. ss_list *ss_prev ; // Maillon précédent lors de la lecture. int mac_list_size = sizeof(mac_list) ; int ss_list_size = sizeof(ss_list) ; mac_list mac_list_lu ; ss_list ss_list_lu ; /* Ouverture du fichier */ fd = open(file, O_RDONLY) ; if (fd < 0) { perror("Impossible d'ouvrir le fichier d'entrée ") ; return ERR_OPENING_FILE ; } /* Lecture des données */ while (read(fd, &mac_list_lu, mac_list_size) == mac_list_size) // Lecture du premier champ { /* Allocation du maillon courant */ if (*results == NULL) { *results = malloc(mac_list_size) ; // Création de la liste ptr = *results ; } else { ptr->next = malloc(mac_list_size) ; // Création du maillon suivant ptr = ptr->next ; } *ptr = mac_list_lu ; /* Lecture de la sous-liste */ ss_prev = NULL ; ss_ptr = ptr->samples_list ; while (ss_ptr != NULL) { if (read(fd, &ss_list_lu, ss_list_size) != ss_list_size) // Lecture d'un maillon ss_list. perror("Erreur de lecture (ss_list) ") ; else // Si on a bien lu un maillon entier : { if (ss_prev == NULL) // Si c'est le premier maillon, { ptr->samples_list = malloc(ss_list_size) ; // allocation du premier maillon. ss_ptr = ptr->samples_list ; } else // Si ce n'est pas le premier maillon, { ss_prev->next = malloc(ss_list_size) ; // allocation d'un nouveau maillon. ss_ptr = ss_prev->next ; } *ss_ptr = ss_list_lu ; ss_prev = ss_ptr ; ss_ptr = ss_ptr->next ; } } if (ss_prev != NULL) ss_prev->next = NULL ; } if (ptr != NULL) ptr->next = NULL ; /* Fermeture du fichier */ if (close(fd) != 0) perror("Erreur lors de la fermeture du fichier de sortie ") ; return 0 ; }