[i-c] Support fichiers config listener/aggregator

Ajout du support des fichiers de configuration et des arguments
(libconfuse / getopt) pour les modules aggregator et listener.
Corrections pour le module client.

git-svn-id: https://pif.pu-pm.univ-fcomte.fr/svn/loc@88 785a6c6c-259e-4ff1-8b91-dc31627914f0
This commit is contained in:
Matteo Cypriani 2009-04-15 12:15:49 +00:00
parent 0d7946e3db
commit f1791d816a
10 changed files with 240 additions and 54 deletions

View File

@ -67,6 +67,7 @@ purge :
help :
@echo -e "Bibliothèques nécessaires à la compilation :\n\
libpcap0.8-dev\n\
libconfuse-dev\n\
libiw-dev\n\
\n\
Cibles possibles :\n\

View File

@ -56,6 +56,7 @@ purge :
help :
@echo -e "Bibliothèques nécessaires à la compilation :\n\
libpcap0.8-dev\n\
libconfuse-dev\n\
libowlps1.0 (fournie)\n\
\n\
Cibles possibles :\n\

View File

@ -9,3 +9,4 @@
* apd : permettre d'utiliser un nom d'hôte putôt qu'une IP pour le serveur d'agrégation.
* Permettre de choisir soi-même le port des communications, aussi bien sur le mobile (demande de localisation), que sur les AP et le serveur d'agrégation. Pour l'instant, les ports sont gérés grâce aux constantes AGGREGATE_DEFAULT_PORT et LOC_REQUEST_DEFAULT_PORT.
→ Fait pour le port d'agrégation, dans owlps-listener et owlps-aggregator.

View File

@ -21,7 +21,7 @@ CFLAGS=-O2 -W -Wall -Wstrict-prototypes -O -I.
DEPFLAGS=-MMD
XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS)
PICFLAG=-fPIC
LIBS=-lpthread ../../libowlps/libowlps.so.1.0
LIBS=-lpthread -lconfuse ../../libowlps/libowlps.so.1.0
## Cibles de compilation standard ##
@ -62,6 +62,7 @@ purge : clean
help :
@echo -e "Bibliothèques nécessaires à la compilation :\n\
libconfuse-dev\n\
libowlps1.0 (fournie)\n\
\n\
Cibles possibles :\n\

View File

@ -7,25 +7,25 @@
#include "../../libowlps/owlps.h"
#include <confuse.h>
//#define TIMESTAMP // Décommenter pour afficher le timestamp à chaque ligne du fichier de sortie.
#define AGGREGATE_TIMEOUT 1500 // Timeout d'agrégation (en millisecondes)
#define KEEP_TIMEOUT 3000 // Temps que l'on conserve les données dans la liste (en millisecondes)
#define CHECK_INTERVAL 500000 // Temps entre deux vérifications de la liste (en micro-secondes)
/* Arguments du programme */
#define ARGC 2
#define ARGV_OUTPUT_FILE 1
/* Arguments & configuration du programme */
#define OPTIONS "f:l:o:a:k:c:" // Chaîne pour getopt
#define DEFAULT_CONFIG_FILE "/usr/local/etc/owlps/owlps-aggregator.conf"
#define DEFAULT_AGGREGATE_TIMEOUT 1500 // Timeout d'agrégation (en millisecondes)
#define DEFAULT_KEEP_TIMEOUT 3000 // Temps que l'on conserve les données dans la liste (en millisecondes)
#define DEFAULT_CHECK_INTERVAL 500000 // Temps entre deux vérifications de la liste (en micro-secondes)
/* Codes d'erreur */
#define ERR_NO_MESSAGE_RECEIVED 1 // Erreur lors de la lecture sur la socket
#define ERR_CREATING_SOCKET 2 // Erreur lors de la création de la socket d'écoute
#define ERR_BAD_USAGE 3 // Mauvais appel au programme
#define ERR_PARSING_CONFIG_FILE 4 // Erreur lors de la lecture du fichier de configuration
/* Liste chaînée des informations concernant un couple MAC / séquence */

View File

@ -8,7 +8,7 @@
#define DEBUG
char *out_file ;
cfg_t *cfg ; // Structure contenant la configuration
int main(int argc, char **argv)
@ -24,18 +24,113 @@ int main(int argc, char **argv)
pthread_t thread ; // Thread pour la fonction de surveillance de la liste d'informations agrégées
char *ap_mac_string, *mobile_mac_string ; // Pointeurs pour retour de mac_bytes_to_string()
if (argc != ARGC)
cfg_opt_t opts[] = { // Options reconnues par confuse dans le fichier de config
CFG_INT("listening_port", AGGREGATE_DEFAULT_PORT, CFGF_NONE), // Port d'écoute
CFG_STR("output_file", "", CFGF_NONE), // Fichier de sortie
CFG_INT("aggregate_timeout", DEFAULT_AGGREGATE_TIMEOUT, CFGF_NONE), // Timeout d'agrégation (en millisecondes)
CFG_INT("keep_timeout", DEFAULT_KEEP_TIMEOUT, CFGF_NONE), // Temps que l'on conserve les données dans la liste (en millisecondes)
CFG_INT("check_interval", DEFAULT_CHECK_INTERVAL, CFGF_NONE), // Temps entre deux vérifications de la liste (en micro-secondes)
CFG_END() } ;
char *config_file ; // Nom du fichier de configuration
int opt ; // Retour de getopt
/* L'option -f sert à spécifier un fichier de configuration alternatif,
* on regarde en premier si elle est présente */
do
opt = getopt(argc, argv, OPTIONS) ;
while (opt != 'f' && opt != -1) ;
if (opt == 'f')
{
config_file = malloc((strlen(optarg) + 1) * sizeof(char)) ;
strcpy(config_file, optarg) ;
}
else // Si -f n'est pas présente, on utilise le fichier de config par défaut
{
config_file = malloc((strlen(DEFAULT_CONFIG_FILE) + 1) * sizeof(char)) ;
strcpy(config_file, DEFAULT_CONFIG_FILE) ;
}
/* Lecture du fichier de configuration */
cfg = cfg_init(opts, CFGF_NONE) ; // Initialisation des options
if (cfg_parse(cfg, config_file) == CFG_PARSE_ERROR)
{
free(config_file) ;
return ERR_PARSING_CONFIG_FILE ;
}
free(config_file) ;
/* Lecture des arguments de la ligne de commandes */
optind = 1 ; // On reprend l'analyse des arguments au début
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
{
case 'f' : // Fichier de configuration
// Déjà traité.
break ;
case 'l' :
cfg_setint(cfg, "listening_port", strtol(optarg, NULL, 0)) ;
break ;
case 'o' :
cfg_setstr(cfg, "output_file", optarg) ;
break ;
case 'a' :
cfg_setint(cfg, "aggregate_timeout", strtol(optarg, NULL, 0)) ;
break ;
case 'k' :
cfg_setint(cfg, "keep_timeout", strtol(optarg, NULL, 0)) ;
break ;
case 'c' :
cfg_setint(cfg, "check_interval", strtol(optarg, NULL, 0)) ;
break ;
default :
print_usage(argv[0]) ;
return ERR_BAD_USAGE ;
}
}
/* Vérification des arguments */
// output_file //
if (cfg_getstr(cfg, "output_file")[0] == '\0')
{
fprintf(stderr, "Erreur ! Vous devez spécifier un fichier de sortie.\n") ;
print_usage(argv[0]) ;
return ERR_BAD_USAGE ;
}
// aggregate_timeout //
if (cfg_getint(cfg, "aggregate_timeout") < 0)
{
#ifdef DEBUG
fprintf(stderr, "Attention ! aggregate_timeout n'admet pas de valeur négative : application de la valeur par défaut.\n") ;
#endif // DEBUG
cfg_setint(cfg, "aggregate_timeout", DEFAULT_AGGREGATE_TIMEOUT) ;
}
// keep_timeout //
if (cfg_getint(cfg, "keep_timeout") < 0)
{
#ifdef DEBUG
fprintf(stderr, "Attention ! keep_timeout n'admet pas de valeur négative : application de la valeur par défaut.\n") ;
#endif // DEBUG
cfg_setint(cfg, "keep_timeout", DEFAULT_KEEP_TIMEOUT) ;
}
// check_interval //
if (cfg_getint(cfg, "check_interval") < 0)
{
#ifdef DEBUG
fprintf(stderr, "Attention ! check_interval n'admet pas de valeur négative : application de la valeur par défaut.\n") ;
#endif // DEBUG
cfg_setint(cfg, "check_interval", DEFAULT_CHECK_INTERVAL) ;
}
#ifdef DEBUG
/* Affichage de la configuration */
fprintf(stderr, "Configuration :\n") ;
cfg_print(cfg, stderr) ;
#endif // DEBUG
run = TRUE ;
/* Fichier de sortie */
out_file = malloc((strlen(argv[ARGV_OUTPUT_FILE]) + 1) * sizeof(char)) ;
strcpy(out_file, argv[ARGV_OUTPUT_FILE]) ;
/* Mise en place des gestionnaires de signaux */
sigemptyset(&action.sa_mask) ;
action.sa_handler = sigint_handler ;
@ -44,10 +139,10 @@ int main(int argc, char **argv)
sigaction(SIGTERM, &action, NULL) ;
/* Création de la socket UDP */
if ((sockfd = create_udp_listening_socket(AGGREGATE_DEFAULT_PORT)) < 0)
if ((sockfd = create_udp_listening_socket(cfg_getint(cfg, "listening_port"))) < 0)
{
fprintf(stderr, "Erreur ! Impossible d'écouter sur le port %d.\n", AGGREGATE_DEFAULT_PORT) ;
exit(ERR_CREATING_SOCKET) ;
fprintf(stderr, "Erreur ! Impossible d'écouter sur le port %ld.\n", cfg_getint(cfg, "listening_port")) ;
return ERR_CREATING_SOCKET ;
}
/* Création du thread */
@ -98,8 +193,8 @@ int main(int argc, char **argv)
}
(void) close(sockfd) ; // Fermeture de la socket
free_couple_list(&couples) ; // Nettoyage
free(out_file) ;
free_couple_list(&couples) ; // Nettoyage de la liste
cfg_free(cfg) ; // Nettoyage de la configuration
printf("%s : fin.\n", argv[0]) ;
return ret ;
@ -118,7 +213,7 @@ void* monitor_couple_list(couple_list **couples)
char *ap_mac_string ;
unsigned long sub ; // Résultat de sub_date().
fd = fopen(out_file, "a") ; // Ouverture du fichier de sortie en ajout
fd = fopen(cfg_getstr(cfg, "output_file"), "a") ; // Ouverture du fichier de sortie en ajout
if (fd == NULL) // Si ouverture échouée,
{
perror("Impossible d'ouvrir le fichier de sortie ") ;
@ -139,14 +234,14 @@ void* monitor_couple_list(couple_list **couples)
if (couple_ptr->info != NULL) // Si le couple atteint n'a pas déjà été traité
{
if (sub > AGGREGATE_TIMEOUT) // Si le timeout est atteint,
if (sub > (unsigned long) cfg_getint(cfg, "aggregate_timeout")) // Si le timeout est atteint,
{
printf("* Timeout dépassé.") ;
#ifdef DEBUG
printf(" sub=%lu > AGGREGATE_TIMEOUT=%d\n", sub, AGGREGATE_TIMEOUT) ;
#else
printf(" sub=%lu > aggregate_timeout=%ld\n", sub, cfg_getint(cfg, "aggregate_timeout")) ;
#else // DEBUG
putchar('\n') ;
#endif
#endif // DEBUG
#ifdef TIMESTAMP
fprintf(fd, "%llu;", timeval_to_ms(couple_ptr->request_time)) ; // Inscription de la date de la demande (sur le mobile) dans le fichier
@ -171,16 +266,16 @@ void* monitor_couple_list(couple_list **couples)
}
}
else if (sub > KEEP_TIMEOUT) // Si le couple a été traité et que le temps de garde est écoulé
else if (sub > (unsigned long) cfg_getint(cfg, "keep_timeout")) // Si le couple a été traité et que le temps de garde est écoulé
{
couple_list *couple_tmp = couple_ptr ;
printf("* Délai de garde dépassé.") ;
#ifdef DEBUG
printf(" sub=%lu > KEEP_TIMEOUT=%d\n", sub, KEEP_TIMEOUT) ;
#else
printf(" sub=%lu > keep_timeout=%ld\n", sub, cfg_getint(cfg, "keep_timeout")) ;
#else // DEBUG
putchar('\n') ;
#endif
#endif // DEBUG
couple_ptr = couple_ptr->next ;
@ -200,7 +295,7 @@ void* monitor_couple_list(couple_list **couples)
}
fflush(NULL) ;
usleep(CHECK_INTERVAL) ; // On attend avant de vérifier à nouveau
usleep(cfg_getint(cfg, "check_interval")) ; // On attend avant de vérifier à nouveau
}
/* Fermeture du fichier */
@ -379,6 +474,6 @@ void print_couple_info(couple_info_list *info)
void print_usage(char *prog)
{
printf("Usage :\n\
\t%s fichier_sortie\n\
\t%s [-f config_file] [-l listening_port] [-a aggregate_timeout] [-k keep_timeout] [-c check_interval] -o output_file\n\
", prog) ;
}

View File

@ -2,7 +2,6 @@
* This file is part of the rtap localisation project.
*/
#include <stdlib.h>
#include "../../libowlps/owlps.h"
#define DEBUG
@ -20,6 +19,7 @@
#define DEFAULT_DELAY_CALIB 50000 // Délai entre chaque émission de paquet lors de la calibration (en microsecondes)
#define DEFAULT_DELAY_NORMAL 25000 // Délai entre chaque émission de paquet dans le cas d'une demande de localisation (en microsecondes)
/* Arguments du programme */
#define OPTIONS "d:i:t:n:"
@ -82,8 +82,7 @@ int main(int argc, char *argv[])
options.delay = strtol(optarg, NULL, 0) ;
break ;
case 'n' :
// options.nb_pkt = strtol(optarg, NULL, 0) ;
options.nb_pkt = atoi(optarg) ;
options.nb_pkt = strtol(optarg, NULL, 0) ;
break ;
default :
print_usage(argv[0]) ;
@ -117,15 +116,21 @@ int main(int argc, char *argv[])
}
/* Vérifications des arguments et initialisation des données non initialisées */
if (options.delay == -1) // Délai non spécifié, application des valeurs par défaut
if (options.delay < 0) // Délai non spécifié ou mauvais, application des valeurs par défaut
{
#ifdef DEBUG
fprintf(stderr, "Attention ! delay : application de la valeur par défaut.\n") ;
#endif // DEBUG
if (is_calibration_request)
options.delay = DEFAULT_DELAY_CALIB ;
else
options.delay = DEFAULT_DELAY_NORMAL ;
}
if (options.nb_pkt == -1) // Nombre de paquets non spécifié, application des valeurs par défaut
if (options.nb_pkt < 1) // Nombre de paquets non spécifié ou mauvais, application des valeurs par défaut
{
#ifdef DEBUG
fprintf(stderr, "Attention ! nb_pkt : application de la valeur par défaut.\n") ;
#endif // DEBUG
if (is_calibration_request)
options.nb_pkt = DEFAULT_NBPKT_CALIB ;
else

View File

@ -21,7 +21,7 @@ CFLAGS=-O2 -W -Wall -Wstrict-prototypes -O -I.
DEPFLAGS=-MMD
XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS)
PICFLAG=-fPIC
LIBS=-lm -lpcap -lpthread ../../libowlps/libowlps.so.1.0
LIBS=-lm -lpcap -lpthread -lconfuse ../../libowlps/libowlps.so.1.0
## Cibles de compilation standard ##
@ -63,6 +63,7 @@ purge : clean
help :
@echo -e "Bibliothèques nécessaires à la compilation :\n\
libpcap0.8-dev\n\
libconfuse-dev\n\
libowlps1.0 (fournie)\n\
\n\
Cibles possibles :\n\

View File

@ -8,6 +8,7 @@
#include "../../libowlps/owlps.h"
#include <pcap.h>
#include <confuse.h>
// Pour la fonction get_mac_addr() :
#include <netinet/if_ether.h>
@ -19,16 +20,15 @@
#define ERR_CREATING_SOCKET 1 // Erreur lors de la création de la socket d'envoi
#define ERR_OPENING_IFACE 2 // Erreur lors de l'ouverture de l'interface de capture
#define ERR_BAD_USAGE 3 // Mauvais appel au programme
#define ERR_PARSING_CONFIG_FILE 4 // Erreur lors de la lecture du fichier de configuration
/* Arguments du programme */
#define ARGC 4
enum {ARGV_AGGREG_IP=1, ARGV_RTAP_IFACE, ARGV_WIFI_IFACE} ;
/* Arguments & configuration du programme */
#define OPTIONS "f:d:r:w:" // Chaîne pour getopt
#define DEFAULT_CONFIG_FILE "/usr/local/etc/owlps/owlps-listener.conf"
/* En-têtes des fonctions */
void* keep_mode_monitor(char *iface) ;
int capture(char *capture_iface, char *aggregated_ip, BOOL print_values) ;
int capture(char *capture_iface, char *aggregation_ip, unsigned int aggregation_port, BOOL print_values) ;
void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, int sockfd, struct sockaddr_in *server, BOOL print_values) ;
void get_mac_addr(char *eth, unsigned char mac_bytes[6]) ;
void print_usage(char *prog) ;

View File

@ -18,11 +18,89 @@ int main(int argc, char *argv[])
int ret ; // Code de retour du programme
pthread_t thread ; // Thread pour le repassage en mode monitor
if (argc != ARGC)
cfg_opt_t opts[] = { // Options reconnues par confuse dans le fichier de config
CFG_STR("aggregation_ip", "127.0.0.1", CFGF_NONE), // Adresse IP du serveur d'agrégation (défaut : boucle locale)
CFG_INT("aggregation_port", AGGREGATE_DEFAULT_PORT, CFGF_NONE), // Port sur le serveur d'agrégation
CFG_STR("rtap_iface", "", CFGF_NONE), // Interface radiotap utilisée pour la capture
CFG_STR("wifi_iface", "", CFGF_NONE), // Interface physique correspondante (utilisée pour récupérer l'adresse MAC)
CFG_END() } ;
cfg_t *cfg ; // Structure contenant la configuration
char *config_file ; // Nom du fichier de configuration
int opt ; // Retour de getopt
/* L'option -f sert à spécifier un fichier de configuration alternatif,
* on regarde en premier si elle est présente */
do
opt = getopt(argc, argv, OPTIONS) ;
while (opt != 'f' && opt != -1) ;
if (opt == 'f')
{
config_file = malloc((strlen(optarg) + 1) * sizeof(char)) ;
strcpy(config_file, optarg) ;
}
else // Si -f n'est pas présente, on utilise le fichier de config par défaut
{
config_file = malloc((strlen(DEFAULT_CONFIG_FILE) + 1) * sizeof(char)) ;
strcpy(config_file, DEFAULT_CONFIG_FILE) ;
}
/* Lecture du fichier de configuration */
cfg = cfg_init(opts, CFGF_NONE) ; // Initialisation des options
if (cfg_parse(cfg, config_file) == CFG_PARSE_ERROR)
{
free(config_file) ;
return ERR_PARSING_CONFIG_FILE ;
}
free(config_file) ;
/* Lecture des arguments de la ligne de commandes */
optind = 1 ; // On reprend l'analyse des arguments au début
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
{
case 'f' : // Fichier de configuration
// Déjà traité.
break ;
case 'd' :
cfg_setstr(cfg, "aggregation_ip", optarg) ;
break ;
case 'p' :
cfg_setint(cfg, "aggregation_port", strtol(optarg, NULL, 0)) ;
break ;
case 'r' :
cfg_setstr(cfg, "rtap_iface", optarg) ;
break ;
case 'w' :
cfg_setstr(cfg, "wifi_iface", optarg) ;
break ;
default :
print_usage(argv[0]) ;
return ERR_BAD_USAGE ;
}
}
/* Vérification des arguments */
if (cfg_getstr(cfg, "rtap_iface")[0] == '\0')
{
fprintf(stderr, "Erreur ! Vous devez spécifier une interface radiotap pour la capture.\n") ;
print_usage(argv[0]) ;
return ERR_BAD_USAGE ;
}
if (cfg_getstr(cfg, "wifi_iface")[0] == '\0')
{
#ifdef DEBUG
fprintf(stderr, "Attention ! Aucune interface Wi-Fi spécifiée. Utilisation de l'interface radiotap (%s) à la place.\n", cfg_getstr(cfg, "rtap_iface")) ;
#endif // DEBUG
cfg_setstr(cfg, "wifi_iface", cfg_getstr(cfg, "rtap_iface")) ;
}
#ifdef DEBUG
/* Affichage de la configuration */
fprintf(stderr, "Configuration :\n") ;
cfg_print(cfg, stderr) ;
#endif // DEBUG
run = TRUE ;
@ -34,14 +112,16 @@ int main(int argc, char *argv[])
sigaction(SIGTERM, &action, NULL) ;
/* Création du thread */
pthread_create(&thread, NULL, (void *) &keep_mode_monitor, argv[ARGV_WIFI_IFACE]) ;
pthread_create(&thread, NULL, (void *) &keep_mode_monitor, cfg_getstr(cfg, "wifi_iface")) ;
get_mac_addr(argv[ARGV_WIFI_IFACE], mac) ;
get_mac_addr(cfg_getstr(cfg, "wifi_iface"), mac) ;
mac_string = mac_bytes_to_string(mac) ;
printf("Ma mac est : %s\n", mac_string) ;
free(mac_string) ;
ret = capture(argv[ARGV_RTAP_IFACE], argv[ARGV_AGGREG_IP], TRUE) ;
ret = capture(cfg_getstr(cfg, "rtap_iface"), cfg_getstr(cfg, "aggregation_ip"), cfg_getint(cfg, "aggregation_port"), TRUE) ;
cfg_free(cfg) ; // Nettoyage de la configuration
printf("%s : fin.\n", argv[0]) ;
return ret ;
@ -68,7 +148,7 @@ void* keep_mode_monitor(char *iface)
/* Capture des paquets en utilisant l'interface "capture_iface".
* Les données capturées sont envoyées au serveur d'aggrégation dont l'IP est "aggregated_ip".
*/
int capture(char *capture_iface, char *aggregated_ip, BOOL print_values)
int capture(char *capture_iface, char *aggregation_ip, unsigned int aggregation_port, BOOL print_values)
{
pcap_t *handle ; // Descripteur de capture de paquets
char errbuf[PCAP_ERRBUF_SIZE] ; // Message d'erreur
@ -91,7 +171,7 @@ int capture(char *capture_iface, char *aggregated_ip, BOOL print_values)
}
/* Ouverture de la socket UDP vers le serveur d'aggrégation */
sockfd = create_udp_sending_socket(aggregated_ip, AGGREGATE_DEFAULT_PORT, &server, &client);
sockfd = create_udp_sending_socket(aggregation_ip, aggregation_port, &server, &client);
if (sockfd < 0)
{
perror("Erreur ! Impossible de créer la socket vers le serveur d'aggrégation \n");
@ -142,7 +222,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *p
if (IS_RETRY(raw_packet_flags))
printf("Retry : pas à traiter\n") ;
}
#endif
#endif // DEBUG
if (raw_packet_type == RAW_PACKET_TYPE_DATA // Si le paquet est de type data,
&& data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE + 9] == RAW_PACKET_PROTO_UDP // et de protocole UDP (9 : position du champ "Protocol" de l'en-tête IP),
@ -339,9 +419,10 @@ void get_mac_addr(char *eth, unsigned char mac_bytes[6])
void print_usage(char *prog)
{
printf("Usage :\n\
\t%s ip_agrégation rtap_iface wifi_iface\n\
- ip_agrégation est l'adresse IP du serveur d'agrégation.\n\
\t%s [-f config_file] [-d ip_agrégation] [-p port_agrégation] -r rtap_iface [-w wifi_iface]\n\
- ip_agrégation est l'adresse IP du serveur d'agrégation (par défaut : 127.0.0.1), et port_agrégation le port sur lequel il écoute (par défaut : %d).\n\
- rtap_iface est l'interface de capture radiotap.\n\
- wifi_iface est l'interface physique correspondant à rtap_iface.\n\
", prog) ;
- wifi_iface est l'interface physique correspondant à rtap_iface (par défaut : rtap_iface).\n\
Note : tous les paramètres sont facultatifs si les options correspondantes sont renseignées dans un fichier de configuration. L'option -f permet de spécifier un fichier de configuration alternatif (par défaut : %s).\n\
", prog, AGGREGATE_DEFAULT_PORT, DEFAULT_CONFIG_FILE) ;
}