From: Jorge Pereira Date: Tue, 17 May 2022 14:07:20 +0000 (-0300) Subject: radsniff: Add '-Z' option allowing to dump the packets (#4504) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5279fa7b07854aa91f9eaf9ffbc65f625d1be707;p=thirdparty%2Ffreeradius-server.git radsniff: Add '-Z' option allowing to dump the packets (#4504) * log: Fix fr_pair_list_log() to accept level identation parameter * log: Fix fr_log_init_file() 'fd' set * log: Fix fr_log_close() 'dst' check * radsniff: Add '-Z' option allowing to dump the packets --- diff --git a/src/bin/radsniff.c b/src/bin/radsniff.c index eda92f72abe..02fd1115b38 100644 --- a/src/bin/radsniff.c +++ b/src/bin/radsniff.c @@ -26,6 +26,7 @@ RCSID("$Id$") +#include #include #include @@ -33,6 +34,7 @@ RCSID("$Id$") #include #include #include +#include #include #include #include @@ -56,6 +58,7 @@ static fr_rb_tree_t *request_tree = NULL; static fr_rb_tree_t *link_tree = NULL; static fr_event_list_t *events; static bool cleanup; +static int packets_count = 1; // Used in '$PATH/${packet}.txt.${count}' static int self_pipe[2] = {-1, -1}; //!< Signals from sig handlers @@ -463,7 +466,7 @@ static void rs_packet_print_fancy(uint64_t count, rs_status_t status, fr_pcap_t char vector[(RADIUS_AUTH_VECTOR_LENGTH * 2) + 1]; fr_pair_list_sort(list, fr_pair_cmp_by_da); - fr_pair_list_log(&default_log, list); + fr_pair_list_log(&default_log, 4, list); fr_base16_encode(&FR_SBUFF_OUT(vector, sizeof(vector)), &FR_DBUFF_TMP(packet->vector, RADIUS_AUTH_VECTOR_LENGTH)); @@ -472,6 +475,56 @@ static void rs_packet_print_fancy(uint64_t count, rs_status_t status, fr_pcap_t } } +static void rs_packet_save_in_output_dir(uint64_t count, UNUSED rs_status_t status, UNUSED fr_pcap_t *handle, + fr_radius_packet_t *packet, fr_pair_list_t *list, + UNUSED struct timeval *elapsed, UNUSED struct timeval *latency, bool response, bool body) +{ + fr_log_t output_file; + char vector[(RADIUS_AUTH_VECTOR_LENGTH * 2) + 1]; + char const *packet_type = response ? "reply" : "request"; + char filename[2048]; + + if (!body) return; + + snprintf(filename, sizeof(filename), "%s/%s.%d.txt", conf->output_dir, packet_type, packets_count); + + if (fr_debug_lvl > 0) { + DEBUG2("Saving %s in %s", packet_type, filename); + } + + /* ensure to remove existing file */ + fr_unlink(filename); + + if (fr_log_init_file(&output_file, filename) < 0) { + ERROR("Failed opening %s output file.", filename); + usage(64); + } + + output_file.print_level = false; + output_file.timestamp = L_TIMESTAMP_OFF; + + /* dump the packet into filesystem */ + fr_pair_list_sort(list, fr_pair_cmp_by_da); + fr_pair_list_log(&output_file, 0, list); + + /* then append the Authenticator-Field */ + fr_base16_encode(&FR_SBUFF_OUT(vector, sizeof(vector)), + &FR_DBUFF_TMP(packet->vector, RADIUS_AUTH_VECTOR_LENGTH)); + + fprintf(output_file.handle, "Authenticator-Field = 0x%s\n", vector); + + if (fr_log_close(&output_file) < 0) { + ERROR("Failed closing %s output file.", filename); + usage(64); + } + + /* + * We need to have $PATH/{request,reply}.txt with the same ID + * to be possible cross the packets. + */ + if ((count % 2) == 0) packets_count++; +} + static inline void rs_packet_print(rs_request_t *request, uint64_t count, rs_status_t status, fr_pcap_t *handle, fr_radius_packet_t *packet, fr_pair_list_t *list, struct timeval *elapsed, struct timeval *latency, @@ -2224,6 +2277,7 @@ static NEVER_RETURNS void usage(int status) fprintf(output, " -N The instance name passed to the collectd plugin.\n"); fprintf(output, " -O Write statistics to this collectd server.\n"); #endif + fprintf(output, " -Z Dump the packets in /{requests,reply}.${count}.txt\n"); fr_exit_now(status); } @@ -2297,7 +2351,7 @@ int main(int argc, char *argv[]) /* * Get options */ - while ((c = getopt(argc, argv, "ab:c:C:d:D:e:Ef:hi:I:l:L:mp:P:qr:R:s:Svw:xXW:T:P:N:O:")) != -1) { + while ((c = getopt(argc, argv, "ab:c:C:d:D:e:Ef:hi:I:l:L:mp:P:qr:R:s:Svw:xXW:T:P:N:O:Z:")) != -1) { switch (c) { case 'a': { @@ -2467,6 +2521,25 @@ int main(int argc, char *argv[]) } break; + case 'Z': + { + char *p = optarg; + size_t len = strlen(p); + + conf->to_output_dir = true; + + /* Strip the last '/' */ + if (p[len-1] == '/') p[len-1] = '\0'; + + conf->output_dir = p; + + if (fr_mkdir(NULL, conf->output_dir, -1, 0755, NULL, NULL) < 0) { + ERROR("Failed to create directory %s: %s", conf->output_dir, fr_syserror(errno)); + usage(64); + } + break; + } + case 'T': conf->stats.timeout = atoi(optarg); if (conf->stats.timeout <= 0) { @@ -2575,6 +2648,8 @@ int main(int argc, char *argv[]) if (conf->list_attributes) { conf->logger = rs_packet_print_csv; + } else if (conf->to_output_dir) { + conf->logger = rs_packet_save_in_output_dir; } else if (fr_debug_lvl > 0) { conf->logger = rs_packet_print_fancy; } @@ -2786,16 +2861,20 @@ int main(int argc, char *argv[]) if (!fr_pair_list_empty(&conf->filter_request_vps)){ DEBUG2(" RADIUS request filter :"); - fr_pair_list_log(&default_log, &conf->filter_request_vps); + fr_pair_list_log(&default_log, 4, &conf->filter_request_vps); } if (conf->filter_response_code) { DEBUG2(" RADIUS response code : [%s]", fr_packet_codes[conf->filter_response_code]); } + if (conf->to_output_dir) { + DEBUG2(" Writing packets in : [%s/{requests,reply}.${count}.txt]", conf->output_dir); + } + if (!fr_pair_list_empty(&conf->filter_response_vps)){ DEBUG2(" RADIUS response filter :"); - fr_pair_list_log(&default_log, &conf->filter_response_vps); + fr_pair_list_log(&default_log, 4, &conf->filter_response_vps); } } diff --git a/src/bin/radsniff.h b/src/bin/radsniff.h index 6e21f121c6c..c810b77176c 100644 --- a/src/bin/radsniff.h +++ b/src/bin/radsniff.h @@ -263,6 +263,9 @@ struct rs { bool to_file; //!< Were writing pcap data to files. bool to_stdout; //!< Were writing pcap data to stdout. + bool to_output_dir; //!< Were writing attributes into directory. + char const *output_dir; //!< Where we should save the files $PATH/requests.txt and $PATH/reply.txt + bool daemonize; //!< Daemonize and write PID out to file. char const *pidfile; //!< File to write PID to. diff --git a/src/lib/util/pair.h b/src/lib/util/pair.h index e6972cf8c49..2f60015e28c 100644 --- a/src/lib/util/pair.h +++ b/src/lib/util/pair.h @@ -689,7 +689,7 @@ static inline fr_slen_t CC_HINT(nonnull(2,4)) void fr_pair_fprint(FILE *, fr_pair_t const *vp) CC_HINT(nonnull); -#define fr_pair_list_log(_log, _list) _fr_pair_list_log(_log, 4, NULL, _list, __FILE__, __LINE__); +#define fr_pair_list_log(_log, _lvl, _list) _fr_pair_list_log(_log, _lvl, NULL, _list, __FILE__, __LINE__); void _fr_pair_list_log(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line) CC_HINT(nonnull(1,4)); diff --git a/src/protocols/radius/list.c b/src/protocols/radius/list.c index 1141efa8cc7..750192d9890 100644 --- a/src/protocols/radius/list.c +++ b/src/protocols/radius/list.c @@ -798,7 +798,7 @@ void fr_packet_header_log(fr_log_t const *log, fr_radius_packet_t *packet, bool void fr_packet_log(fr_log_t const *log, fr_radius_packet_t *packet, fr_pair_list_t *list, bool received) { fr_packet_header_log(log, packet, received); - if (fr_debug_lvl >= L_DBG_LVL_1) fr_pair_list_log(log, list); + if (fr_debug_lvl >= L_DBG_LVL_1) fr_pair_list_log(log, 4, list); #ifndef NDEBUG if (fr_debug_lvl >= L_DBG_LVL_4) fr_radius_packet_log_hex(log, packet); #endif