[Listener] Add -v -q -m + other modifications

owlps-listener :
* Détail des erreurs d'ouverture / parcours du fichier de configuration.
* Ajout des option -v et -q permettant de choisir si le programme doit
  être verbeux ou silencieux.
* Modification des en-têtes de capture() et read_packet() pour utiliser
  la structure de configuration plutôt que des passages d'arguments.
  Note : peut-être serait-il bien de déplacer read_packet() dans
  capture() (à la place de got_packet) pour éviter le passage incessant
  des arguments sockfd et server.
* Ajout de l'option -m permettant de choisir le mode (actif, passif,
  mixte).
* Préparation de l'implantation du mode passif (dans read_packet).

git-svn-id: https://pif.pu-pm.univ-fcomte.fr/svn/loc@106 785a6c6c-259e-4ff1-8b91-dc31627914f0
This commit is contained in:
Matteo Cypriani 2009-08-04 10:02:52 +00:00
parent c2f18d715e
commit 24fef29457
2 changed files with 81 additions and 23 deletions

View File

@ -36,16 +36,16 @@
/* Arguments & configuration du programme */ /* Arguments & configuration du programme */
#define OPTIONS "d:f:kl:p:r:w:" // Chaîne pour getopt #define OPTIONS "m:d:f:kl:p:r:w:v" // Chaîne pour getopt
#define DEFAULT_CONFIG_FILE "/usr/local/etc/owlps/owlps-listener.conf" #define DEFAULT_CONFIG_FILE "/usr/local/etc/owlps/owlps-listener.conf"
enum {MODE_ACTIVE = 'a', MODE_PASSIVE = 'p', MODE_MIXED = 'm'} ;
/* En-têtes des fonctions */ /* En-têtes des fonctions */
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
void* keep_mode_monitor(char *iface) ; void* keep_mode_monitor(char *iface) ;
#endif // USE_PTHREAD #endif // USE_PTHREAD
int capture(char *capture_iface, char *aggregation_ip, unsigned int aggregation_port, BOOL print_values) ; int capture(void) ;
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 read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, int sockfd, struct sockaddr_in *server) ;
void get_mac_addr(char *eth, unsigned char mac_bytes[6]) ; void get_mac_addr(char *eth, unsigned char mac_bytes[6]) ;
void print_usage(char *prog) ; void print_usage(char *prog) ;
@ -56,6 +56,8 @@ void print_usage(char *prog) ;
*/ */
/* Macros utilisant libconfuse : */ /* Macros utilisant libconfuse : */
#ifdef USE_CONFIG_FILE #ifdef USE_CONFIG_FILE
#define SET_MODE(MODE) (cfg_setint(cfg, "mode", (MODE)))
#define GET_MODE() (cfg_getint(cfg, "mode"))
#define SET_AGGREGATION_IP(IP) (cfg_setstr(cfg, "aggregation_ip", (IP))) #define SET_AGGREGATION_IP(IP) (cfg_setstr(cfg, "aggregation_ip", (IP)))
#define GET_AGGREGATION_IP() (cfg_getstr(cfg, "aggregation_ip")) #define GET_AGGREGATION_IP() (cfg_getstr(cfg, "aggregation_ip"))
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
@ -70,9 +72,14 @@ void print_usage(char *prog) ;
#define GET_RTAP_IFACE() (cfg_getstr(cfg, "rtap_iface")) #define GET_RTAP_IFACE() (cfg_getstr(cfg, "rtap_iface"))
#define SET_WIFI_IFACE(IFACE) (cfg_setstr(cfg, "wifi_iface", (IFACE))) #define SET_WIFI_IFACE(IFACE) (cfg_setstr(cfg, "wifi_iface", (IFACE)))
#define GET_WIFI_IFACE() (cfg_getstr(cfg, "wifi_iface")) #define GET_WIFI_IFACE() (cfg_getstr(cfg, "wifi_iface"))
#define SET_VERBOSE() (cfg_setbool(cfg, "verbose", cfg_true))
#define UNSET_VERBOSE() (cfg_setbool(cfg, "verbose", cfg_false))
#define GET_VERBOSE() (cfg_getbool(cfg, "verbose"))
/* Macros utilisant la structure maison : */ /* Macros utilisant la structure maison : */
#else // USE_CONFIG_FILE #else // USE_CONFIG_FILE
#define SET_MODE(MODE) (options.mode = (MODE))
#define GET_MODE() (options.mode)
#define SET_AGGREGATION_IP(IP) (strncpy(options.aggregation_ip, (IP), 16)) #define SET_AGGREGATION_IP(IP) (strncpy(options.aggregation_ip, (IP), 16))
#define GET_AGGREGATION_IP() (options.aggregation_ip) #define GET_AGGREGATION_IP() (options.aggregation_ip)
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
@ -87,6 +94,9 @@ void print_usage(char *prog) ;
#define GET_RTAP_IFACE() (options.rtap_iface) #define GET_RTAP_IFACE() (options.rtap_iface)
#define SET_WIFI_IFACE(IFACE) (strncpy(options.wifi_iface, (IFACE), IFNAMSIZ+1)) #define SET_WIFI_IFACE(IFACE) (strncpy(options.wifi_iface, (IFACE), IFNAMSIZ+1))
#define GET_WIFI_IFACE() (options.wifi_iface) #define GET_WIFI_IFACE() (options.wifi_iface)
#define SET_VERBOSE() (options.verbose = TRUE)
#define UNSET_VERBOSE() (options.verbose = FALSE)
#define GET_VERBOSE() (options.verbose)
#endif // USE_CONFIG_FILE #endif // USE_CONFIG_FILE

View File

@ -14,6 +14,7 @@ cfg_t *cfg ; // Structure contenant la configuration
#else // USE_CONFIG_FILE // Si on n'utilise pas libconfuse, on déclare une #else // USE_CONFIG_FILE // Si on n'utilise pas libconfuse, on déclare une
struct { // structure qui servira à stocker les options getopt : struct { // structure qui servira à stocker les options getopt :
char mode ;
char aggregation_ip[16] ; char aggregation_ip[16] ;
long aggregation_port ; long aggregation_port ;
long listening_port ; long listening_port ;
@ -22,14 +23,17 @@ struct { // structure qui servira à stocker les options getopt
#endif // USE_PTHREAD #endif // USE_PTHREAD
char rtap_iface[IFNAMSIZ + 1] ; char rtap_iface[IFNAMSIZ + 1] ;
char wifi_iface[IFNAMSIZ + 1] ; char wifi_iface[IFNAMSIZ + 1] ;
BOOL verbose ;
} options = { // et on initalise les options par défaut : } options = { // et on initalise les options par défaut :
MODE_ACTIVE,
"127.0.0.1", "127.0.0.1",
AGGREGATE_DEFAULT_PORT, AGGREGATE_DEFAULT_PORT,
#ifdef USE_PTHREAD #ifdef USE_PTHREAD
FALSE, FALSE,
#endif // USE_PTHREAD #endif // USE_PTHREAD
"", "",
"" "",
FALSE
} ; } ;
#endif // USE_CONFIG_FILE #endif // USE_CONFIG_FILE
@ -45,6 +49,7 @@ int main(int argc, char *argv[])
#ifdef USE_CONFIG_FILE // Si on utilise libconfuse, on déclare les options : #ifdef USE_CONFIG_FILE // Si on utilise libconfuse, on déclare les options :
cfg_opt_t opts[] = { // Options reconnues par confuse dans le fichier de config cfg_opt_t opts[] = { // Options reconnues par confuse dans le fichier de config
CFG_INT("mode", MODE_ACTIVE, CFGF_NONE), // Mode d'écoute : a pour actif, p pour passif, m pour mixte (défaut : a)
CFG_STR("aggregation_ip", "127.0.0.1", CFGF_NONE), // Adresse IP du serveur d'agrégation (défaut : boucle locale) 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 d'envoi sur le serveur d'agrégation CFG_INT("aggregation_port", AGGREGATE_DEFAULT_PORT, CFGF_NONE), // Port d'envoi sur le serveur d'agrégation
CFG_INT("listening_port", LOC_REQUEST_DEFAULT_PORT, CFGF_NONE), // Port d'écoute des demandes des mobiles CFG_INT("listening_port", LOC_REQUEST_DEFAULT_PORT, CFGF_NONE), // Port d'écoute des demandes des mobiles
@ -53,6 +58,7 @@ int main(int argc, char *argv[])
#endif // USE_PTHREAD #endif // USE_PTHREAD
CFG_STR("rtap_iface", "", CFGF_NONE), // Interface radiotap utilisée pour la capture 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_STR("wifi_iface", "", CFGF_NONE), // Interface physique correspondante (utilisée pour récupérer l'adresse MAC)
CFG_BOOL("verbose", cfg_false, CFGF_NONE), // Afficher les paquets capturés ou pas
CFG_END() } ; CFG_END() } ;
char *config_file ; // Nom du fichier de configuration char *config_file ; // Nom du fichier de configuration
@ -84,8 +90,13 @@ int main(int argc, char *argv[])
/* Lecture du fichier de configuration */ /* Lecture du fichier de configuration */
cfg = cfg_init(opts, CFGF_NONE) ; // Initialisation des options cfg = cfg_init(opts, CFGF_NONE) ; // Initialisation des options
if (cfg_parse(cfg, config_file) == CFG_PARSE_ERROR) switch (cfg_parse(cfg, config_file))
{ {
case CFG_FILE_ERROR :
fprintf(stderr, "Erreur lors de l'ouverture du fichier de configuration « %s » : %s.\n", config_file, strerror(errno)) ;
break ;
case CFG_PARSE_ERROR :
fprintf(stderr, "Erreur lors de la lecture du fichier de configuration « %s » !\n", config_file) ;
free(config_file) ; free(config_file) ;
return ERR_PARSING_CONFIG_FILE ; return ERR_PARSING_CONFIG_FILE ;
} }
@ -115,12 +126,21 @@ int main(int argc, char *argv[])
case 'l' : case 'l' :
SET_LISTENING_PORT(strtol(optarg, NULL, 0)) ; SET_LISTENING_PORT(strtol(optarg, NULL, 0)) ;
break ; break ;
case 'm' :
SET_MODE(optarg[0]) ;
break ;
case 'p' : case 'p' :
SET_AGGREGATION_PORT(strtol(optarg, NULL, 0)) ; SET_AGGREGATION_PORT(strtol(optarg, NULL, 0)) ;
break ; break ;
case 'q' :
UNSET_VERBOSE() ;
break ;
case 'r' : case 'r' :
SET_RTAP_IFACE(optarg) ; SET_RTAP_IFACE(optarg) ;
break ; break ;
case 'v' :
SET_VERBOSE() ;
break ;
case 'w' : case 'w' :
SET_WIFI_IFACE(optarg) ; SET_WIFI_IFACE(optarg) ;
break ; break ;
@ -131,6 +151,17 @@ int main(int argc, char *argv[])
} }
/* Vérification des arguments */ /* Vérification des arguments */
switch (GET_MODE())
{
case MODE_ACTIVE :
case MODE_MIXED :
case MODE_PASSIVE :
break ;
default :
fprintf(stderr, "Erreur ! Mode « %c » inconnu.\n", (char) GET_MODE()) ;
print_usage(argv[0]) ;
return ERR_BAD_USAGE ;
}
if (GET_RTAP_IFACE()[0] == '\0') if (GET_RTAP_IFACE()[0] == '\0')
{ {
fprintf(stderr, "Erreur ! Vous devez spécifier une interface radiotap pour la capture.\n") ; fprintf(stderr, "Erreur ! Vous devez spécifier une interface radiotap pour la capture.\n") ;
@ -192,7 +223,7 @@ wifi_iface = \"%s\"\n\
printf("Ma mac est : %s\n", mac_string) ; printf("Ma mac est : %s\n", mac_string) ;
free(mac_string) ; free(mac_string) ;
ret = capture(GET_RTAP_IFACE(), GET_AGGREGATION_IP(), GET_AGGREGATION_PORT(), TRUE) ; ret = capture() ;
#ifdef USE_CONFIG_FILE #ifdef USE_CONFIG_FILE
cfg_free(cfg) ; // Nettoyage de la configuration cfg_free(cfg) ; // Nettoyage de la configuration
@ -222,10 +253,11 @@ void* keep_mode_monitor(char *iface)
/* Capture des paquets en utilisant l'interface "capture_iface". /* Capture des paquets en utilisant l'interface RTAP figurant dans les options.
* Les données capturées sont envoyées au serveur d'aggrégation dont l'IP est "aggregated_ip". * Les données capturées sont envoyées au serveur d'aggrégation dont l'IP
* figure également dans les options.
*/ */
int capture(char *capture_iface, char *aggregation_ip, unsigned int aggregation_port, BOOL print_values) int capture()
{ {
pcap_t *handle ; // Descripteur de capture de paquets pcap_t *handle ; // Descripteur de capture de paquets
char errbuf[PCAP_ERRBUF_SIZE] ; // Message d'erreur char errbuf[PCAP_ERRBUF_SIZE] ; // Message d'erreur
@ -236,19 +268,21 @@ int capture(char *capture_iface, char *aggregation_ip, unsigned int aggregation_
/* Sous-fonction de traitement des paquets capturés */ /* Sous-fonction de traitement des paquets capturés */
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{ {
read_packet(args, header, packet, sockfd, &server, print_values) ; // On appelle la fonction read_packet() avec les mêmes arguments, plus "print_values" qui indique si on doit afficher le paquet. // On appelle la fonction read_packet() avec les mêmes arguments,
// plus les informations concernant le serveur :
read_packet(args, header, packet, sockfd, &server) ;
} }
handle = pcap_open_live(capture_iface, BUFSIZ, 1, 1000, errbuf) ; // Début de la capture handle = pcap_open_live(GET_RTAP_IFACE(), BUFSIZ, 1, 1000, errbuf) ; // Début de la capture
if (handle == NULL) // Le lancement de la capture a-t-il échoué ? 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) ; fprintf(stderr, "Impossible d'ouvrir l'interface « %s » : %s\n", GET_RTAP_IFACE(), errbuf) ;
return ERR_OPENING_IFACE ; return ERR_OPENING_IFACE ;
} }
/* Ouverture de la socket UDP vers le serveur d'aggrégation */ /* Ouverture de la socket UDP vers le serveur d'aggrégation */
sockfd = create_udp_sending_socket(aggregation_ip, aggregation_port, &server, &client); sockfd = create_udp_sending_socket(GET_AGGREGATION_IP(), GET_AGGREGATION_PORT(), &server, &client);
if (sockfd < 0) if (sockfd < 0)
{ {
perror("Erreur ! Impossible de créer la socket vers le serveur d'aggrégation \n"); perror("Erreur ! Impossible de créer la socket vers le serveur d'aggrégation \n");
@ -270,7 +304,7 @@ int capture(char *capture_iface, char *aggregation_ip, unsigned int aggregation_
/* Traite un paquet et l'envoie au serveur d'agrégation sur la socket UDP "sockfd", au serveur "server". */ /* Traite un paquet et l'envoie au serveur d'agrégation sur la socket UDP "sockfd", au serveur "server". */
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 read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, int sockfd, struct sockaddr_in *server)
{ {
unsigned char *data = (unsigned char *) packet ; // Recopie dans data l'adresse du paquet capturé 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 short rtap_bytes ; // Taille des données reçues
@ -311,7 +345,9 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *p
} }
#endif // DEBUG #endif // DEBUG
if (raw_packet_type == RAW_PACKET_TYPE_DATA // Si le paquet est de type data, /* Mode actif */
if ((GET_MODE() == MODE_ACTIVE || GET_MODE() == MODE_MIXED)
&& 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), && 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),
&& dst_port == LOC_REQUEST_DEFAULT_PORT // et le port de destination est le bon, && dst_port == LOC_REQUEST_DEFAULT_PORT // et le port de destination est le bon,
&& ! IS_RETRY(raw_packet_flags)) // et ce n'est pas un Retry. && ! IS_RETRY(raw_packet_flags)) // et ce n'est pas un Retry.
@ -329,7 +365,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *p
switch(packet_type) switch(packet_type)
{ {
case PACKET_TYPE_NORMAL : case PACKET_TYPE_NORMAL :
if (print_values) if (GET_VERBOSE())
printf("\nPaquet normal reçu.\n") ; printf("\nPaquet normal reçu.\n") ;
couple.direction = 0 ; couple.direction = 0 ;
couple.x_position = 0 ; couple.x_position = 0 ;
@ -338,7 +374,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *p
break ; break ;
case PACKET_TYPE_CALIBRATION : case PACKET_TYPE_CALIBRATION :
if (print_values) if (GET_VERBOSE())
printf("\nPaquet de calibration reçu.\n") ; printf("\nPaquet de calibration reçu.\n") ;
couple.direction = data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE + IP_HEADER_SIZE + UDP_HEADER_SIZE + 9]; couple.direction = data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE + IP_HEADER_SIZE + UDP_HEADER_SIZE + 9];
memcpy(&couple.x_position, &data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE + IP_HEADER_SIZE + UDP_HEADER_SIZE + 10], sizeof(float)); memcpy(&couple.x_position, &data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE + IP_HEADER_SIZE + UDP_HEADER_SIZE + 10], sizeof(float));
@ -347,7 +383,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *p
break ; break ;
default : default :
if (print_values) if (GET_VERBOSE())
printf("\nPaquet bizarre reçu.\n") ; printf("\nPaquet bizarre reçu.\n") ;
fprintf(stderr, "Erreur ! Type de paquet inconnu (%d).\n", packet_type) ; fprintf(stderr, "Erreur ! Type de paquet inconnu (%d).\n", packet_type) ;
return ; return ;
@ -392,7 +428,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *p
case RTAP_ANTENNASIGNALDBM: case RTAP_ANTENNASIGNALDBM:
memcpy(&(couple.antenna_signal_dbm), &data[rtap_position], RTAP_L_ANTENNASIGNALDBM) ; memcpy(&(couple.antenna_signal_dbm), &data[rtap_position], RTAP_L_ANTENNASIGNALDBM) ;
check[RTAP_ANTENNASIGNALDBM] = TRUE; check[RTAP_ANTENNASIGNALDBM] = TRUE;
if (print_values) if (GET_VERBOSE())
printf("Antenna Signal : %d dBm\n", couple.antenna_signal_dbm - 0x100); printf("Antenna Signal : %d dBm\n", couple.antenna_signal_dbm - 0x100);
rtap_position += RTAP_L_ANTENNASIGNALDBM ; rtap_position += RTAP_L_ANTENNASIGNALDBM ;
break ; break ;
@ -437,7 +473,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *p
rtap_presentflags /= 2 ; rtap_presentflags /= 2 ;
} }
if (print_values) if (GET_VERBOSE())
{ {
char *ap_mac_string = mac_bytes_to_string(couple.ap_mac_addr_bytes) ; char *ap_mac_string = mac_bytes_to_string(couple.ap_mac_addr_bytes) ;
char *mobile_mac_string = mac_bytes_to_string(couple.mobile_mac_addr_bytes) ; char *mobile_mac_string = mac_bytes_to_string(couple.mobile_mac_addr_bytes) ;
@ -475,6 +511,12 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *p
return ; return ;
} }
} }
/* Mode passif */
else if (GET_MODE() == MODE_PASSIVE || GET_MODE() == MODE_MIXED)
{
/* TODO */
}
} }
@ -510,12 +552,18 @@ void get_mac_addr(char *eth, unsigned char mac_bytes[6])
void print_usage(char *prog) void print_usage(char *prog)
{ {
printf("Usage :\n\ printf("Usage :\n\
\t%s [-f config_file] [-d ip_agrégation] [-l listening_port] [-p port_agrégation] -r rtap_iface [-w wifi_iface] [-k]\n\ \t%s [-f config_file] [-m mode] [-d ip_agrégation] [-l listening_port] [-p port_agrégation] -r rtap_iface [-w wifi_iface] [-k] [-v|-q]\n\
- L'option -f permet de spécifier un fichier de configuration alternatif (le fichier de configuration par défaut ne sera pas lu). Disponible uniquement si le programme a é compilé avec le support de libconfuse.\n\ - L'option -f permet de spécifier un fichier de configuration alternatif (le fichier de configuration par défaut ne sera pas lu). Disponible uniquement si le programme a é compilé avec le support de libconfuse.\n\
- mode est le mode de fonctionnement : a(ctif), p(assif), m(ixte) (par défaut : a).\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\ - 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\ - rtap_iface est l'interface de capture radiotap.\n\
- wifi_iface est l'interface physique correspondant à rtap_iface (par défaut : rtap_iface).\n\ - wifi_iface est l'interface physique correspondant à rtap_iface (par défaut : rtap_iface).\n\
- L'option -k active le maintien actif du mode monitor. À utiliser avec des pilotes bogués. Disponible uniquement si le programme a é compilé avec le support des threads POSIX.\n\ - L'option -k active le maintien actif du mode monitor. À utiliser avec des pilotes bogués. Disponible uniquement si le programme a é compilé avec le support des threads POSIX.\n\
- L'option -v rend le programme bavard (affichage des paquets capturés) ; l'option -q annule le bavardage s'il est activé par ailleurs (e.g. fichier de configuration). Par défaut le mode verbeux est désactivé.\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\ 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) ; ",
prog,
AGGREGATE_DEFAULT_PORT,
DEFAULT_CONFIG_FILE
) ;
} }