From 6716b37bb63ce73f826760956b379c2477ba81ec Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Thu, 14 Feb 2008 08:45:47 +0000 Subject: [PATCH] Import initial (TX) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Travail de l'UV TX52 à l'UTBM, par Matteo Cypriani et Pierre-Frédéric Rossel, sur une base de code de Frédéric Lassabe. Code en « version finale revue et augmentée » envoyée à Frédéric Lassabe le 03/07/2007. git-svn-id: https://pif.pu-pm.univ-fcomte.fr/svn/loc@6 785a6c6c-259e-4ff1-8b91-dc31627914f0 --- loc-mobile/code/librtapanalyser/Makefile | 146 ++++ .../code/librtapanalyser/librtapanalyser.c | 629 ++++++++++++++++++ .../code/librtapanalyser/rtapanalyser.h | 130 ++++ loc-mobile/code/librtapanalyser/tx.c | 217 ++++++ 4 files changed, 1122 insertions(+) create mode 100644 loc-mobile/code/librtapanalyser/Makefile create mode 100644 loc-mobile/code/librtapanalyser/librtapanalyser.c create mode 100644 loc-mobile/code/librtapanalyser/rtapanalyser.h create mode 100644 loc-mobile/code/librtapanalyser/tx.c diff --git a/loc-mobile/code/librtapanalyser/Makefile b/loc-mobile/code/librtapanalyser/Makefile new file mode 100644 index 0000000..d078723 --- /dev/null +++ b/loc-mobile/code/librtapanalyser/Makefile @@ -0,0 +1,146 @@ +# Répertoire d'installation +PREFIX=/usr/local +INSTALL_DIR= $(PREFIX)/sbin +INSTALL_LIB= $(PREFIX)/lib +INSTALL_INC= $(PREFIX)/include +INSTALL_MAN= $(PREFIX)/share/man + +# Compilateur +CC = gcc + +# Autres outils +AR = ar +RANLIB = ranlib + +# Commandes d'installation et de désinstallation +RM=rm -fv +CP=cp -v + +# Variables générales +LIB_CIBLE=librtapanalyser +VERSION=1.0 + +# Cibles à construire +STATIC=$(LIB_CIBLE).a +DYNAMIC=$(LIB_CIBLE).so.$(VERSION) +PROGS=tx +HEADER=rtapanalyser.h +#HEADERS= + +# Composition de la bibliothèque +OBJS=$(LIB_CIBLE).o + +# Flags +CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I. +DEPFLAGS=-MMD +XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) +PICFLAG=-fPIC +LIBS=-lm -lpcap +#STRIPFLAGS= -Wl,-s + + +## Cibles de compilation standard ## + +all : dynamic static $(PROGS) +dynamic : $(DYNAMIC) +static : $(STATIC) + +% : %.o + $(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ +%.o : %.c $(HEADER) + $(CC) $(XCFLAGS) -c $< +%.so : %.c $(HEADER) + $(CC) $(XCFLAGS) $(PICFLAG) -c -o $@ $< + +# Compilation du programme d'exemple +tx : tx.o $(DYNAMIC) $(HEADER) + +# Compilation de la bibliothèque dynamique +$(DYNAMIC) : $(OBJS:.o=.so) + $(CC) -shared -o $@ -Wl,-soname,$@ $(STRIPFLAGS) $(LIBS) -lc $^ + +# Compilation de la bibliothèque statique +$(STATIC) : $(OBJS:.o=.so) + $(RM) $@ + $(AR) cru $@ $^ + $(RANLIB) $@ + + +## Installation ## + +install : install-tx install-static install-dynamic + +install-dynamic : install-header $(DYNAMIC) + @$(CP) $(DYNAMIC) $(INSTALL_LIB) &&\ + chmod 644 $(INSTALL_LIB)/$(DYNAMIC) &&\ + chown root:root $(INSTALL_LIB)/$(DYNAMIC) &&\ + echo -e "\n!!! Installation de la bibliothèque dynamique effectuée avec succès.\n!!! Ajoutez une ligne « $(INSTALL_LIB) » dans le fichier /etc/ld.so.conf\n ou dans un nouveau fichier de /etc/ld.so.conf.d/, si ce n'est déjà fait.\n!!! Exécutez ldconfig ensuite.\n" + +install-static : install-header $(STATIC) + @$(CP) $(STATIC) $(INSTALL_LIB) &&\ + chmod 644 $(INSTALL_LIB)/$(STATIC) &&\ + chown root:root $(INSTALL_LIB)/$(STATIC) + +install-header : $(HEADER) + @$(CP) $(HEADER) $(INSTALL_INC) &&\ + chmod 644 $(INSTALL_INC)/$(HEADER) &&\ + chown root:root $(INSTALL_INC)/$(HEADER) + +install-tx : $(PROGS) + @$(CP) $(PROGS) $(INSTALL_DIR) + @cd $(INSTALL_DIR) ; chown root:root $(PROGS) ; chmod 755 $(PROGS) + + +## Désinstallation ## + +uninstall : uninstall-dynamic uninstall-static uninstall-tx + +uninstall-dynamic : uninstall-header + @$(RM) $(INSTALL_LIB)/$(DYNAMIC) + ldconfig + +uninstall-static : uninstall-header + @$(RM) $(INSTALL_LIB)/$(STATIC) + +uninstall-header : + @$(RM) $(INSTALL_INC)/$(HEADER) + +uninstall-tx : + @cd $(INSTALL_DIR) && $(RM) $(PROGS) + + +## Nettoyage ## + +clean : + @$(RM) *~ *.o $(LIB_CIBLE).so *.d + +purge : clean + @$(RM) $(DYNAMIC) $(STATIC) $(PROGS) + + +## Aide ## + +help : + @echo -e "Bibliothèques nécessaires à la compilation :\n\ + libpcap0.8-dev\n\ + \n\ + Cibles possibles :\n\ + all (cible par défaut) : Compile la bibliothèque et le programme d'exemple (tx).\n\ + dynamic : Compile la bibilothèque partagée (.so).\n\ + static : Compile la bibliothèque statique (.a).\n\ + tx : Compile le programme d'exemple.\n\ + \n\ + install : Installe la bibliothèque partagée, statique, ainsi que le programme d'exemple.\n\ + install-dynamic : N'installe que la bibliothèque partagée.\n\ + install-static : N'installe que la bibliothèque statique.\n\ + install-tx : N'installe que le programme d'exemple.\n\ + \n\ + uninstall : Désinstalle tout ce qu'il est possible de désinstaller.\n\ + uninstall-dynamic : Désinstalle la bibliothèque partagée.\n\ + uninstall-static : Désinstalle la bibliothèque statique.\n\ + uninstall-tx : Désinstalle le programme d'exemple.\n\ + \n\ + clean : Supprime les fichiers temporaires.\n\ + purge : Supprime le résultat de la compilation.\n\ + \n\ + Note : l'installation se fait dans l'arborescence $(PREFIX). Modifiez la variable PREFIX du Makefile pour changer ce comportement." diff --git a/loc-mobile/code/librtapanalyser/librtapanalyser.c b/loc-mobile/code/librtapanalyser/librtapanalyser.c new file mode 100644 index 0000000..1cf856f --- /dev/null +++ b/loc-mobile/code/librtapanalyser/librtapanalyser.c @@ -0,0 +1,629 @@ +/* + * This is the rtapanalyser library, Wi-Fi packet sniffer and analyser, + * thanks to the radiotap header of each packet. + */ + + +#include "rtapanalyser.h" + + +/* Convertit une adresse MAC en octets en une chaîne de caractères */ +char* mac_bytes_to_string(unsigned char *mac_binary) +{ + char *ret = malloc(sizeof(char) * 18) ; + + sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x", mac_binary[0], mac_binary[1], mac_binary[2], mac_binary[3], mac_binary[4], mac_binary[5]) ; + ret[17] = '\0' ; + return ret ; +} + + + +/* Convertit un identifiant de canal en son numéro (0 si la fréquence est erronée) */ +char frequency_to_channel(unsigned short channel) +{ + char c = 0 ; // Résultat + + switch (channel) + { + case 2412 : + c = 1 ; + break ; + case 2417 : + c = 2 ; + break ; + case 2422 : + c = 3 ; + break ; + case 2427 : + c = 4 ; + break ; + case 2432 : + c = 5 ; + break ; + case 2437 : + c = 6 ; + break ; + case 2442 : + c = 7 ; + break ; + case 2447 : + c = 8 ; + break ; + case 2452 : + c = 9 ; + break ; + case 2457 : + c = 10 ; + break ; + case 2462 : + c = 11 ; + break ; + case 2467 : + c = 12 ; + break ; + case 2472 : + c = 13 ; + break ; + case 2477 : + c = 14 ; + break ; + } + + return c ; +} + + + +/* Retourne le temps écoulé entre deux dates */ +unsigned int sub_date(struct timeb sup, struct timeb inf) +{ + unsigned int ret = 0 ; + unsigned int sec_sup = sup.time ; + unsigned int sec_inf = inf.time ; + + if(sup.millitm < inf.millitm) + { + ret = 1000 + sup.millitm - inf.millitm ; + sec_sup-- ; + } + else + ret = sup.millitm - inf.millitm ; + ret += (sec_sup - sec_inf) * 1000 ; + + return ret ; +} + + + +/* Compare deux adresses MAC : retourne TRUE si elles sont égales, FALSE sinon */ +BOOL mac_cmp(unsigned char *mac1, unsigned char *mac2) +{ + int i ; + for(i=0 ; i < 6 ; i++) + if(mac1[i] != mac2[i]) + return FALSE ; + return TRUE ; +} + + + +/* 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 + + 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) + { + //printf("%s\n", mac_bytes_to_string(mac_ptr->mac_addr_bytes)) ; // On convertit l'adresse MAC en chaîne de caractères pour l'afficher + 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_bytes_to_string(mac_ptr->mac_addr_bytes)) ; + 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_bytes_to_string(mac_ptr->mac_addr_bytes), frequency_to_channel(channel), channel, channel_type, data_rate_average, antenna_signal_average, antenna_noise_average) ; + if (verbose) + printf("\n\n") ; + + 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) ; + + + //printf("Début de l'enregistrement des résulats dans le fichier « %s »...\n", file) ; + + + /* 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) + { + //printf("Enregistrement (%s)...\n", mac_bytes_to_string(ptr->mac_addr_bytes)) ; + + /* 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 ; + + //printf("Début de la lecture du fichier « %s »...\n", file) ; + + /* 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 + { + //printf("Lecture (%s)...\n", mac_bytes_to_string(mac_list_lu.mac_addr_bytes)) ; // Affichage de la MAC actuelle. + + /* 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 ; + } + //printf("Fin de la lecture.\n") ; + 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 ; +} + + + +/* Capture des paquets en utilisant l'interface "capture_iface" pendant "capture_time" mili-secondes, 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 timeb 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. + } + + + if (capture_time < 1) // Le temps de capture doit être d'au moins 1 ms. + { + fprintf(stderr, "Durée de capture incorrecte !\n") ; + return ERR_CAPTURE_TIME_FORMAT ; + } + + + 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) ; + } + + ftime(&tbegin) ; // Récupère l'heure courante (heure du lancement de la capture) + + while(1) + { + pcap_loop(handle, 1, got_packet, NULL) ; // Collecte 1 paquet et appelle la fonction got_packet quand pcaploop a recupéré des paquets + ftime(&tcurrent) ; // 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. + } + + 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) +{ + mac_list *tmp_mac = NULL ; + ss_list *tmp_ss = NULL ; + unsigned char *data = (unsigned char *) packet ; // Recopie dans data l'adresse du paquet capturé + unsigned short int rtap_bytes ; // Taille des données reçues + unsigned char c ; + int i ; + unsigned int rtap_presentflags, rtap_position ; + // unsigned int ss_position = 0 ; + unsigned char mac_addr_binary[6] ; + // unsigned char *mac_addr_string ; + // int rtap_data_size[15] = {8,1,1,4,2,1,1,2,2,2,1,1,1,1,4} ; + int k=0; + + memcpy(&rtap_bytes, &data[2], sizeof(unsigned short int)) ; // 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) + c = 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(c == 0x80) // Si c'est un beacon on le traite + { + memcpy(mac_addr_binary, &data[rtap_bytes+10], 6); // Dans le cas du beacon, l'adresse MAC est 10 octets plus loin + 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(k=0 ; k < 15 ; k++) + tmp_ss->check[k] = FALSE ; + rtap_position = 8 ; // début des champs déterminés par le present flag + + if (print_values) + { + printf("[%s]\n", mac_bytes_to_string(mac_addr_binary)) ; + 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) ; + } + + for(i=0 ; i < 14 ; 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_binary, 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_binary, 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_binary, 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 ; + } + } + } +} diff --git a/loc-mobile/code/librtapanalyser/rtapanalyser.h b/loc-mobile/code/librtapanalyser/rtapanalyser.h new file mode 100644 index 0000000..8800582 --- /dev/null +++ b/loc-mobile/code/librtapanalyser/rtapanalyser.h @@ -0,0 +1,130 @@ +/* + * This is the rtapanalyser library, Wi-Fi packet sniffer and analyser, + * thanks to the radiotap header of each packet. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Type booléen */ +typedef enum {FALSE, TRUE} BOOL ; + + +/* Liste chaînée des valeurs des champs rtap */ +typedef struct _ss_list +{ + unsigned char header_revision ; + unsigned char header_pad ; + unsigned short header_length ; + unsigned short fhss; + unsigned long present_flags ; + unsigned long long mac_timestamp ; + unsigned char flags; + unsigned char data_rate ; + unsigned short channel ; + unsigned short channel_type ; + unsigned char antenna_signal_dbm ; + unsigned char antenna_noise_dbm ; + unsigned char antenna ; + unsigned short lock_quality ; + unsigned short tx_attenuation ; + unsigned short tx_attenuation_db ; + unsigned char tx_attenuation_dbm ; + unsigned char antenna_signal_db ; + unsigned char antenna_noise_db ; + unsigned long fcs ; + BOOL check[15] ; // Champs présents + struct _ss_list *next ; +} ss_list ; + + +/* Liste chaînée des adresses MAC en provenances desquelles on a capturé des paquets */ +typedef struct _mac_list +{ + unsigned short int nb_samples ; // Nombre d'occurrences de l'adresse MAC + unsigned char mac_addr_bytes[6] ; // Adresse MAC en octets + ss_list *samples_list ; // Liste des valeurs capturées pour cette adresse + struct _mac_list *next ; // Élément suivant de la liste +} mac_list ; + + +/* Position des champs fixes de l'en-tête rtap (octets) */ +#define RTAP_P_HREVISION 0 // Header revision +#define RTAP_P_HPAD 1 // Header pad +#define RTAP_P_HLENGTH 2 // Header length +#define RTAP_P_PRESENTFLAGS 4 // Present flags + + +/* Longueur des champs de l'en-tête rtap (octets) */ +#define RTAP_L_HREVISION 1 // Header revision +#define RTAP_L_HPAD 1 // Header pad +#define RTAP_L_HLENGTH 2 // Header length +#define RTAP_L_PRESENTFLAGS 4 // Present flags +#define RTAP_L_MACTS 8 // MAC timestamp +#define RTAP_L_FLAGS 1 // autre champ de flags +#define RTAP_L_RATE 1 // Data rate +#define RTAP_L_CHANNEL 2 // Channel +#define RTAP_L_CHANNELTYPE 2 // Channel type +#define RTAP_L_ANTENNASIGNALDBM 1 // SSI signal dBm +#define RTAP_L_ANTENNANOISEDBM 1 // SSI noise dBm +#define RTAP_L_ANTENNA 1 // Antenna +#define RTAP_L_FHSS 2 +#define RTAP_L_LOCKQUALITY 2 +#define RTAP_L_TXATTENUATION 2 +#define RTAP_L_TXATTENUATIONDB 2 +#define RTAP_L_TXATTENUATIONDBM 1 +#define RTAP_L_ANTENNASIGNALDB 1 // en dB +#define RTAP_L_ANTENNANOISEDB 1 // en dB +#define RTAP_L_FCS 4 +#define RTAP_L_EXT // Non implémenté + + +/* Positions pour affichage (tableau check de ss_list) */ +#define RTAP_MACTS 0 +#define RTAP_FLAGS 1 +#define RTAP_RATE 2 +#define RTAP_CHANNEL 3 // ainsi que RTAP_CHANNELTYPE +#define RTAP_FHSS 4 +#define RTAP_ANTENNASIGNALDBM 5 +#define RTAP_ANTENNANOISEDBM 6 +#define RTAP_LOCKQUALITY 7 +#define RTAP_TXATTENUATION 8 +#define RTAP_TXATTENUATIONDB 9 +#define RTAP_TXATTENUATIONDBM 10 +#define RTAP_ANTENNA 11 +#define RTAP_ANTENNASIGNALDB 12 +#define RTAP_ANTENNANOISEDB 13 +#define RTAP_FCS 14 + + +/* Codes d'erreurs */ +#define ERR_FILENAME 1 // Erreur dans le nom du fichier d'entrée ou de sortie +#define ERR_OPENING_FILE 2 // Erreur lors de l'ouverture du fichier d'entrée ou de sortie +#define ERR_OPENING_IFACE 3 // Erreur lors de l'ouverture de l'interface de capture +#define ERR_CAPTURE_TIME_FORMAT 4 // Format du temps de capture incorrect + + +/* En-têtes des fonctions */ +int capture(char *capture_iface, unsigned long capture_time, mac_list **results, BOOL print_values) ; +void print_mac_list(mac_list *results, BOOL verbose) ; +void print_ss_list(ss_list *ss) ; +void free_mac_list(mac_list **results) ; +int write_mac_list_to_file(char *file, mac_list *results) ; +int read_mac_list_from_file(char *file, mac_list **results) ; + +void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, mac_list **results, BOOL print_values) ; +char* mac_bytes_to_string(unsigned char *mac_binary) ; +char frequency_to_channel(unsigned short channel) ; +unsigned int sub_date(struct timeb sup, struct timeb inf) ; +BOOL mac_cmp(unsigned char *mac1, unsigned char *mac2) ; diff --git a/loc-mobile/code/librtapanalyser/tx.c b/loc-mobile/code/librtapanalyser/tx.c new file mode 100644 index 0000000..261f6e9 --- /dev/null +++ b/loc-mobile/code/librtapanalyser/tx.c @@ -0,0 +1,217 @@ +/* + * This is the rtapanalyser library, Wi-Fi packet sniffer and analyser, + * thanks to the radiotap header of each packet. + */ + + +#include "rtapanalyser.h" + + + +/* Options du programme */ +#define DEFAULT_IFACE "rtap0" // Interface de capture par défaut. +#define DEFAULT_CAPTURE_TIME 5000 // Temps de capture par défaut en milli-secondes. +#define MAX_FILENAME_LENGTH 500 // Longueur maximale du nom des fichiers. +#define MAX_IFACENAME_LENGTH 50 // Longueur maximale du nom de l'interface de capture. +#define MAX_OPT_LENGTH 5 // Longueur maximale des options sur la ligne de commandes. +#define NB_OPTIONS 7 // Nombre d'options. +enum {NUM_OPT_HELP, NUM_OPT_IFACE, NUM_OPT_CAPTURE_TIME, NUM_OPT_OUTPUT, NUM_OPT_INPUT, NUM_OPT_VERB, NUM_OPT_VERB2} ; // Liste des numéros d'options. +#define OPT_HELP "-h" // Option d'affichage de l'aide. +#define OPT_OUTPUT "-o" // Option d'enregistrement des résultats dans un fichier. +#define OPT_INPUT "-i" // Option de lecture des trames enregistrées avec -o. +#define OPT_IFACE "-d" // Option de spécification de l'interface de capture. +#define OPT_CAPTURE_TIME "-t" // Option de spécification du temps de capture. +#define OPT_VERB "-v" // Option de verbosité. +#define OPT_VERB2 "-vv" // Option de verbosité maximale. +#define ERR_BAD_OPTION 50 // Code d'erreur en cas de mauvaise option de ligne de commande. +#define ERR_OPT_INPUT_OUTPUT 51 // Erreur d'incompatibilité entre les deux options entrée et sortie de/vers fichier. + + + +/* Affiche la syntaxe du programme */ +void print_usage(char *prog) +{ + printf("Usage :\n\ +\t%s -h\n\ +\t%s [ -v ] [ -i fichier ]\n\ +\t%s [ -v | -vv ] [ -d interface ] [ -t temps ] [ -o fichier ]\n\ +", prog, prog, prog) ; +} + + + +/* Affiche la syntaxe du programme */ +void print_usage_only(char *prog) +{ + putchar('\n') ; + + print_usage(prog) ; + + printf("\nPour afficher l'aide, tapez « %s -h ».\n", prog) ; +} + + + +/* Affiche l'aide complète du programme */ +void print_help(char *prog) +{ + print_usage(prog) ; + + printf("\n\ +Options :\n\ +\t-h : affiche cette aide.\n\ +\t-v : affichage détaillé.\n\ +\t-vv : affichage très détaillé.\n\ +\t-i fichier : lit les informations depuis le fichier « fichier » plutôt que de tenter de capturer des paquets.\n\ +\t-o fichier : enregistre les informations capturées dans le fichier « fichier ».\n\ +\t-d interface : les paquets sont capturés sur l'interface réseau « interface ». Par défaut, « %s » est utilisée.\n\ +\t-t temps : les paquets sont capturés pendant « temps » millisecondes. Par défaut, « temps » vaut %d.\n\ +\n\ +Note : votre interface de capture doit être en mode « monitor », et supporter radiotap.\n\ +", DEFAULT_IFACE, DEFAULT_CAPTURE_TIME) ; +} + + + +/* Analyse les options de la ligne de commandes */ +void read_options(int argc, char **argv, BOOL *options, char *capture_iface, int *capture_time, char *file) +{ + int i ; // Compteur. + char num_prev_opt = -1 ; // Numéro de la dernière option lue, si elle prend un argument. Ne doit pas être positionné lors de la lecture des options ne prenant pas d'argument ; doit être repositionnée à -1 après le traitement de l'option. + + + /* Initialisation du tableau d'options à FALSE */ + for (i = 0 ; i < NB_OPTIONS ; i++) + options[i] = FALSE ; + + + /* Lecture des options */ + for (i = 1 ; i < argc ; i++) + { + if (num_prev_opt != -1) + { + /* Cas des options suivies d'un argument (exemple : « -o fichier ») */ + switch (num_prev_opt) + { + case NUM_OPT_OUTPUT : + case NUM_OPT_INPUT : + strncpy(file, argv[i], MAX_FILENAME_LENGTH) ; + num_prev_opt = -1 ; + break ; + case NUM_OPT_IFACE : + strncpy(capture_iface, argv[i], MAX_IFACENAME_LENGTH) ; + num_prev_opt = -1 ; + break ; + case NUM_OPT_CAPTURE_TIME : + *capture_time = atoi(argv[i]) ; + num_prev_opt = -1 ; + break ; + } + } + + else if (strncmp(argv[i], OPT_HELP, MAX_OPT_LENGTH) == 0) + { + print_help(argv[0]) ; + exit(0) ; + } + + else if (strncmp(argv[i], OPT_IFACE, MAX_OPT_LENGTH) == 0) + { + options[NUM_OPT_IFACE] = TRUE ; + num_prev_opt = NUM_OPT_IFACE ; + } + + else if (strncmp(argv[i], OPT_CAPTURE_TIME, MAX_OPT_LENGTH) == 0) + { + options[NUM_OPT_CAPTURE_TIME] = TRUE ; + num_prev_opt = NUM_OPT_CAPTURE_TIME ; + } + + else if (strncmp(argv[i], OPT_OUTPUT, MAX_OPT_LENGTH) == 0) + { + options[NUM_OPT_OUTPUT] = TRUE ; + num_prev_opt = NUM_OPT_OUTPUT ; + } + + else if (strncmp(argv[i], OPT_INPUT, MAX_OPT_LENGTH) == 0) + { + options[NUM_OPT_INPUT] = TRUE ; + num_prev_opt = NUM_OPT_INPUT ; + } + + else if (strncmp(argv[i], OPT_VERB, MAX_OPT_LENGTH) == 0) + { + if (options[NUM_OPT_VERB] == TRUE) // Si l'option est déjà présente, + options[NUM_OPT_VERB2] = TRUE ; // on active le deuxième niveau de verbosité. + else + options[NUM_OPT_VERB] = TRUE ; + } + + else if (strncmp(argv[i], OPT_VERB2, MAX_OPT_LENGTH) == 0) + { + options[NUM_OPT_VERB] = TRUE ; + options[NUM_OPT_VERB2] = TRUE ; + } + + else + { + print_usage_only(argv[0]) ; + fprintf(stderr, "Option inconnue « %s » !\n\n", argv[i]) ; + exit(ERR_BAD_OPTION) ; + } + } + + + /* Vérifications des options */ + if (options[NUM_OPT_OUTPUT] == TRUE || options[NUM_OPT_INPUT] == TRUE) + if (file[0] == '\0') + { + fprintf(stderr, "Vous devez spécifier un nom de fichier après les options -i et -o !\n") ; + print_usage_only(argv[0]) ; + exit(ERR_FILENAME) ; + } + if (options[NUM_OPT_OUTPUT] == TRUE && options[NUM_OPT_INPUT] == TRUE) + { + fprintf(stderr, "Les options -i et -o sont incompatibles !\n") ; + print_usage_only(argv[0]) ; + exit(ERR_OPT_INPUT_OUTPUT) ; + } +} + + + +int main(int argc, char **argv) +{ + BOOL options[NB_OPTIONS] ; // Tableau des options présentes. + char capture_iface[MAX_IFACENAME_LENGTH] = DEFAULT_IFACE ; // Interface d'entrée + int capture_time = DEFAULT_CAPTURE_TIME ; // Temps de capture + char file[MAX_FILENAME_LENGTH] = "\0" ; // Nom du fichier à lire ou écrire. + mac_list *results = NULL ; + int ret = 0 ; // Valeur de retour des fonctions appelées. + + /* Lecture des options de la ligne de commande */ + read_options(argc, argv, options, capture_iface, &capture_time, file) ; + + if (options[NUM_OPT_INPUT] == TRUE) // Si l'option INPUT est présente, + { + if ((ret = read_mac_list_from_file(file, &results)) != 0) // Lecture du fichier. + return ret ; + print_mac_list(results, options[NUM_OPT_VERB]) ; // Affichage. + free_mac_list(&results) ; // Nettoyage + return 0 ; + } + + printf("Interface de capture : %s\nTemps de capture : %d\n\n", capture_iface, capture_time) ; + + if ((ret = capture(capture_iface, capture_time, &results, options[NUM_OPT_VERB])) != 0) // Capture de paquets. + return ret ; // On quitte avec le code d'erreur si la capture a mal fini. + + print_mac_list(results, options[NUM_OPT_VERB2]) ; // Affichage des paquets capturés. + + if (options[NUM_OPT_OUTPUT] == TRUE) // Si l'option OUTPUT est présente, + ret = write_mac_list_to_file(file, results) ; + + free_mac_list(&results) ; // Nettoyage + + return ret ; +}