Fix bug where when using a response filter, requests where the response failed the...
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 19 Jun 2014 10:44:42 +0000 (11:44 +0100)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 19 Jun 2014 10:44:42 +0000 (11:44 +0100)
src/include/radsniff.h
src/main/radsniff.c

index 608be28..7dc8ea7 100644 (file)
@@ -161,6 +161,11 @@ typedef struct rs_stats {
                                                        //!< dropping packets, or we run out of memory.
 } rs_stats_t;
 
+typedef struct rs_capture {
+       struct pcap_pkthdr      *header;                //!< PCAP packet header.
+       uint8_t                 *data;                  //!< PCAP packet data.
+} rs_capture_t;
+
 /** Wrapper for RADIUS_PACKET
  *
  * Allows an event to be associated with a request packet.  This is required because we need to disarm
@@ -178,6 +183,11 @@ typedef struct rs_request {
        RADIUS_PACKET           *linked;                //!< The subsequent response or forwarded request the packet
                                                        //!< was linked against.
 
+
+       rs_capture_t            capture[RS_RETRANSMIT_MAX];     //!< Buffered request packets (if a response filter
+                                                               //!< has been applied).
+       rs_capture_t            *capture_p;                     //!< Next packet slot.
+
        uint64_t                rt_req;                 //!< Number of times we saw the same request packet.
        uint64_t                rt_rsp;                 //!< Number of times we saw a retransmitted response
                                                        //!< packet.
index 912897c..d95c76f 100644 (file)
@@ -897,6 +897,89 @@ static int rs_packet_cmp(rs_request_t const *a, rs_request_t const *b)
        return fr_packet_cmp(a->expect, b->expect);
 }
 
+static inline int rs_response_to_pcap(rs_event_t *event, rs_request_t *request, struct pcap_pkthdr const *header,
+                                     uint8_t const *data)
+{
+       if (!event->out) return 0;
+
+       /*
+        *      If we're filtering by response then the requests then the capture buffer
+        *      associated with the request should contain buffered request packets.
+        */
+       if (conf->filter_response) {
+               rs_capture_t *start;
+
+               /*
+                *      Record the current position in the header
+                */
+               start = request->capture_p;
+
+               /*
+                *      Buffer hasn't looped set capture_p to the start of the buffer
+                */
+               if (!start->header) request->capture_p = request->capture;
+
+               /*
+                *      If where capture_p points to, has a header set, write out the
+                *      packet to the PCAP file, looping over the buffer until we
+                *      hit our start point.
+                */
+               if (request->capture_p->header) do {
+                       pcap_dump((void *)event->out->dumper, request->capture_p->header,
+                                 request->capture_p->data);
+                       TALLOC_FREE(request->capture_p->header);
+                       TALLOC_FREE(request->capture_p->data);
+
+                       /* Reset the pointer to the start of the circular buffer */
+                       if (request->capture_p++ >= (request->capture + sizeof(request->capture))) {
+                               request->capture_p = request->capture;
+                       }
+               } while (request->capture_p != start);
+       }
+
+       /*
+        *      Now log the response
+        */
+       pcap_dump((void *)event->out->dumper, header, data);
+
+       return 0;
+}
+
+static inline int rs_request_to_pcap(rs_event_t *event, rs_request_t *request, struct pcap_pkthdr const *header,
+                                    uint8_t const *data)
+{
+       if (!event->out) return 0;
+
+       /*
+        *      If we're filtering by response, then we need to wait to write out the requests
+        */
+       if (conf->filter_response) {
+               /* Free the old capture */
+               if (request->capture_p->header) {
+                       talloc_free(request->capture_p->header);
+                       talloc_free(request->capture_p->data);
+               }
+
+               if (!(request->capture_p->header = talloc(request, struct pcap_pkthdr))) return -1;
+               if (!(request->capture_p->data = talloc_array(request, uint8_t, header->caplen))) {
+                       TALLOC_FREE(request->capture_p->header);
+                       return -1;
+               }
+               memcpy(request->capture_p->header, header, sizeof(struct pcap_pkthdr));
+               memcpy(request->capture_p->data, data, header->caplen);
+
+               /* Reset the pointer to the start of the circular buffer */
+               if (++request->capture_p >= (request->capture + sizeof(request->capture))) {
+                       request->capture_p = request->capture;
+               }
+               return 0;
+       }
+
+       pcap_dump((void *)event->out->dumper, header, data);
+
+       return 0;
+}
+
 /* This is the same as immediately scheduling the cleanup event */
 #define RS_CLEANUP_NOW(_x, _s)\
        {\
@@ -1177,6 +1260,7 @@ static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkt
                        stats->exchange[current->code].interval.unlinked_total++;
                }
 
+               rs_response_to_pcap(event, original, header, data);
                response = true;
                break;
        }
@@ -1265,8 +1349,8 @@ static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkt
                 */
                } else {
                        original = rbtree_finddata(request_tree, &search);
-                       if (original && memcmp(original->expect->vector, current->vector,
-                           sizeof(original->expect->vector)) != 0) {
+                       if (original && (memcmp(original->expect->vector, current->vector,
+                           sizeof(original->expect->vector)) != 0)) {
                                /*
                                 *      ID reused before the request timed out (which may be an issue)...
                                 */
@@ -1329,6 +1413,9 @@ static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkt
                        original->in = event->in;
                        original->stats_req = &stats->exchange[current->code];
 
+                       /* Set the packet pointer to the start of the buffer*/
+                       original->capture_p = original->capture;
+
                        original->packet = talloc_steal(original, current);
                        original->expect = talloc_steal(original, search.expect);
 
@@ -1369,6 +1456,7 @@ static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkt
                        talloc_free(original);
                        return;
                }
+               rs_request_to_pcap(event, original, header, data);
                response = false;
                break;
        }
@@ -1380,10 +1468,6 @@ static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkt
                return;
        }
 
-       if (event->out) {
-               pcap_dump((void *) (event->out->dumper), header, data);
-       }
-
        rs_tv_sub(&header->ts, &start_pcap, &elapsed);
 
        /*