", built on " __DATE__ " at " __TIME__;
static int rs_useful_codes[] = {
- PW_CODE_AUTHENTICATION_REQUEST, //!< RFC2865 - Authentication request
- PW_CODE_AUTHENTICATION_ACK, //!< RFC2865 - Access-Accept
- PW_CODE_AUTHENTICATION_REJECT, //!< RFC2865 - Access-Reject
+ PW_CODE_ACCESS_REQUEST, //!< RFC2865 - Authentication request
+ PW_CODE_ACCESS_ACCEPT, //!< RFC2865 - Access-Accept
+ PW_CODE_ACCESS_REJECT, //!< RFC2865 - Access-Reject
PW_CODE_ACCOUNTING_REQUEST, //!< RFC2866 - Accounting-Request
PW_CODE_ACCOUNTING_RESPONSE, //!< RFC2866 - Accounting-Response
PW_CODE_ACCESS_CHALLENGE, //!< RFC2865 - Access-Challenge
rad_print_hex(packet);
}
- if (conf->print_packet && (fr_debug_flag > 1) && packet->vps) {
- pairsort(&packet->vps, attrtagcmp);
- vp_printlist(fr_log_fp, packet->vps);
+ if (conf->print_packet && (fr_debug_flag > 1)) {
+ char vector[(AUTH_VECTOR_LEN * 2) + 1];
+
+ if (packet->vps) {
+ pairsort(&packet->vps, attrtagcmp);
+ vp_printlist(fr_log_fp, packet->vps);
+ }
+
+ fr_bin2hex(vector, packet->vector, AUTH_VECTOR_LEN);
+ INFO("\tAuthenticator-Field = 0x%s", vector);
}
}
}
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)\
{\
return;
}
}
- if (version == 4) {
+ if ((version == 4) && conf->verify_udp_checksum) {
uint16_t expected;
expected = fr_udp_checksum((uint8_t const *) udp, ntohs(udp->len), udp->checksum,
* recover once some requests timeout, so make an effort to deal
* with allocation failures gracefully.
*/
- current = rad_alloc(conf, 0);
+ current = rad_alloc(conf, false);
if (!current) {
REDEBUG("Failed allocating memory to hold decoded packet");
rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
switch (current->code) {
case PW_CODE_ACCOUNTING_RESPONSE:
- case PW_CODE_AUTHENTICATION_REJECT:
- case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_CHALLENGE:
case PW_CODE_COA_NAK:
case PW_CODE_COA_ACK:
case PW_CODE_DISCONNECT_NAK:
*/
if (conf->filter_response_vps) {
pairsort(¤t->vps, attrtagcmp);
- if (!pairvalidate_relaxed(conf->filter_response_vps, current->vps)) {
+ if (!pairvalidate_relaxed(NULL, conf->filter_response_vps, current->vps)) {
goto drop_response;
}
}
stats->exchange[current->code].interval.unlinked_total++;
}
+ rs_response_to_pcap(event, original, header, data);
response = true;
break;
}
case PW_CODE_ACCOUNTING_REQUEST:
- case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_ACCESS_REQUEST:
case PW_CODE_COA_REQUEST:
case PW_CODE_DISCONNECT_REQUEST:
case PW_CODE_STATUS_SERVER:
*/
} 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)...
*/
* Now verify the packet passes the attribute filter
*/
if (conf->filter_request_vps) {
- if (!pairvalidate_relaxed(conf->filter_request_vps, current->vps)) {
+ if (!pairvalidate_relaxed(NULL, conf->filter_request_vps, current->vps)) {
goto drop_request;
}
}
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);
talloc_free(original);
return;
}
+ rs_request_to_pcap(event, original, header, data);
response = false;
break;
}
return;
}
- if (event->out) {
- pcap_dump((void *) (event->out->dumper), header, data);
- }
-
rs_tv_sub(&header->ts, &start_pcap, &elapsed);
/*
DEBUG("Done reading packets (%s)", event->in->name);
fr_event_fd_delete(events, 0, fd);
- if (fr_event_list_num_fds(events) == 0) {
+ /* Signal pipe takes one slot which is why this is == 1 */
+ if (fr_event_list_num_fds(events) == 1) {
fr_event_loop_exit(events, 1);
}
i++;
}
+ /*
+ * This allows efficient list comparisons later
+ */
+ if (i > 1) fr_quick_sort((void const **)out, 0, i - 1, fr_pointer_cmp);
+
return i;
}
if (vp->type == VT_XLAT) {
vp->type = VT_DATA;
vp->vp_strvalue = vp->value.xlat;
+ vp->length = talloc_array_length(vp->vp_strvalue) - 1;
}
}
return 0;
}
-static int rs_build_flags(int *flags, FR_NAME_NUMBER const *map, char *list)
+static int rs_build_event_flags(int *flags, FR_NAME_NUMBER const *map, char *list)
{
size_t i = 0;
char *p, *tok;
this->in_link_tree = false;
}
-/** Write the last signal to the signal pipe
- *
- * @param sig raised
- */
-static void rs_signal_self(int sig)
-{
- if (write(self_pipe[1], &sig, sizeof(sig)) < 0) {
- ERROR("Failed writing signal %s to pipe: %s", strsignal(sig), fr_syserror(errno));
- exit(EXIT_FAILURE);
- }
-}
-
#ifdef HAVE_COLLECTDC_H
/** Re-open the collectd socket
*
}
#endif
+/** Write the last signal to the signal pipe
+ *
+ * @param sig raised
+ */
+static void rs_signal_self(int sig)
+{
+ if (write(self_pipe[1], &sig, sizeof(sig)) < 0) {
+ ERROR("Failed writing signal %s to pipe: %s", strsignal(sig), fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+}
+
/** Read the last signal from the signal pipe
*
*/
}
}
-
static void NEVER_RETURNS usage(int status)
{
FILE *output = status ? stderr : stdout;
fprintf(output, "options:\n");
fprintf(output, " -a List all interfaces available for capture.\n");
fprintf(output, " -c <count> Number of packets to capture.\n");
+ fprintf(output, " -C Enable UDP checksum validation.\n");
fprintf(output, " -d <directory> Set dictionary directory.\n");
- fprintf(stderr, " -d <raddb> Set configuration directory (defaults to " RADDBDIR ").\n");
- fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(output, " -d <raddb> Set configuration directory (defaults to " RADDBDIR ").\n");
+ fprintf(output, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
fprintf(output, " -e <event>[,<event>] Only log requests with these event flags.\n");
fprintf(output, " Event may be one of the following:\n");
fprintf(output, " - received - a request or response.\n");
fprintf(output, " -S Write PCAP data to stdout.\n");
fprintf(output, " -v Show program version information.\n");
fprintf(output, " -w <file> Write output packets to file.\n");
- fprintf(output, " -x Print more debugging information (defaults to -xx).\n");
+ fprintf(output, " -x Print more debugging information.\n");
fprintf(output, "stats options:\n");
fprintf(output, " -W <interval> Periodically write out statistics every <interval> seconds.\n");
fprintf(output, " -T <timeout> How many milliseconds before the request is counted as lost "
/*
* Get options
*/
- while ((opt = getopt(argc, argv, "ab:c:d:D:e:Ff:hi:I:l:L:mp:P:qr:R:s:Svw:xXW:T:P:N:O:")) != EOF) {
+ while ((opt = getopt(argc, argv, "ab:c:Cd:D:e:Ff:hi:I:l:L:mp:P:qr:R:s:Svw:xXW:T:P:N:O:")) != EOF) {
switch (opt) {
case 'a':
- {
- pcap_if_t *all_devices = NULL;
- pcap_if_t *dev_p;
+ {
+ pcap_if_t *all_devices = NULL;
+ pcap_if_t *dev_p;
- if (pcap_findalldevs(&all_devices, errbuf) < 0) {
- ERROR("Error getting available capture devices: %s", errbuf);
- goto finish;
- }
-
- int i = 1;
- for (dev_p = all_devices;
- dev_p;
- dev_p = dev_p->next) {
- INFO("%i.%s", i++, dev_p->name);
- }
- ret = 0;
+ if (pcap_findalldevs(&all_devices, errbuf) < 0) {
+ ERROR("Error getting available capture devices: %s", errbuf);
goto finish;
}
+ int i = 1;
+ for (dev_p = all_devices;
+ dev_p;
+ dev_p = dev_p->next) {
+ INFO("%i.%s", i++, dev_p->name);
+ }
+ ret = 0;
+ goto finish;
+ }
+
/* super secret option */
case 'b':
conf->buffer_pkts = atoi(optarg);
}
break;
+ /* udp checksum */
+ case 'C':
+ conf->verify_udp_checksum = true;
+ break;
+
case 'd':
radius_dir = optarg;
break;
break;
case 'e':
- if (rs_build_flags((int *) &conf->event_flags, rs_events, optarg) < 0) {
+ if (rs_build_event_flags((int *) &conf->event_flags, rs_events, optarg) < 0) {
usage(64);
}
break;
case 'w':
out = fr_pcap_init(conf, optarg, PCAP_FILE_OUT);
+ if (!out) {
+ ERROR("Failed creating pcap file \"%s\"", optarg);
+ exit(EXIT_FAILURE);
+ }
conf->to_file = true;
break;
usage(64);
}
- link_tree = rbtree_create((rbcmp) rs_rtx_cmp, _unmark_link, 0);
+ link_tree = rbtree_create(conf, (rbcmp) rs_rtx_cmp, _unmark_link, 0);
if (!link_tree) {
ERROR("Failed creating RTX tree");
goto finish;
/*
* Setup the request tree
*/
- request_tree = rbtree_create((rbcmp) rs_packet_cmp, _unmark_request, 0);
+ request_tree = rbtree_create(conf, (rbcmp) rs_packet_cmp, _unmark_request, 0);
if (!request_tree) {
ERROR("Failed creating request tree");
goto finish;
DEBUG2(" Device(s) : [%s]", buff);
talloc_free(buff);
}
- if (conf->to_file || conf->to_stdout) {
+ if (out) {
DEBUG2(" Writing to : [%s]", out->name);
}
if (conf->limit > 0) {
}
}
- assert(out->link_type > 0);
+ assert(out->link_type >= 0);
if (fr_pcap_open(out) < 0) {
ERROR("Failed opening pcap output (%s): %s", out->name, fr_strerror());