]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
radsniff: Add '-Z' option allowing to dump the packets (#4504)
authorJorge Pereira <jpereira@users.noreply.github.com>
Tue, 17 May 2022 14:07:20 +0000 (11:07 -0300)
committerGitHub <noreply@github.com>
Tue, 17 May 2022 14:07:20 +0000 (09:07 -0500)
* 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

src/bin/radsniff.c
src/bin/radsniff.h
src/lib/util/pair.h
src/protocols/radius/list.c

index eda92f72abea993477735406356de0d95b122bb7..02fd1115b38ccf76c8c5e64de0389b2f6d237697 100644 (file)
@@ -26,6 +26,7 @@
 
 RCSID("$Id$")
 
+#include <fcntl.h>
 #include <time.h>
 #include <math.h>
 
@@ -33,6 +34,7 @@ RCSID("$Id$")
 #include <freeradius-devel/radius/list.h>
 #include <freeradius-devel/util/conf.h>
 #include <freeradius-devel/util/event.h>
+#include <freeradius-devel/util/file.h>
 #include <freeradius-devel/util/syserror.h>
 #include <freeradius-devel/util/atexit.h>
 #include <freeradius-devel/util/pair_legacy.h>
@@ -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 <prefix>           The instance name passed to the collectd plugin.\n");
        fprintf(output, "  -O <server>           Write statistics to this collectd server.\n");
 #endif
+       fprintf(output, "  -Z <output_dir>       Dump the packets in <output_dir>/{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);
                }
        }
 
index 6e21f121c6c2823638ea5d29e899e17b6a9cb893..c810b77176c8acdee7e16a4787f25b8bb8b493c4 100644 (file)
@@ -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.
 
index e6972cf8c49deb7618bb878d98fc4cae1b6b0e24..2f60015e28cfcd139a4a3d32a95f4b43751276f6 100644 (file)
@@ -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));
 
index 1141efa8cc7e9888ff5e5671167e06b2efc6c6c4..750192d989049d1e2ba9eed350a3739ac871389b 100644 (file)
@@ -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