27 RCSID(
"$Id: fa4685a91cd335aba0207ccc7d0be898d5eaef9a $")
33 #include <freeradius-devel/autoconf.h>
34 #include <freeradius-devel/radius/list.h>
35 #include <freeradius-devel/util/conf.h>
36 #include <freeradius-devel/util/event.h>
37 #include <freeradius-devel/util/file.h>
38 #include <freeradius-devel/util/syserror.h>
39 #include <freeradius-devel/util/atexit.h>
40 #include <freeradius-devel/util/pair_legacy.h>
41 #include <freeradius-devel/util/base16.h>
42 #include <freeradius-devel/util/pcap.h>
43 #include <freeradius-devel/util/timeval.h>
45 #ifdef HAVE_COLLECTDC_H
46 # include <collectd/client.h>
51 #define RS_ASSERT(_x) if (!(_x) && !fr_cond_assert(_x)) exit(1)
151 if ((chdir(
"/")) < 0) {
159 fp = fopen(pidfile,
"w");
161 fprintf(fp,
"%d\n", (
int) sid);
171 if (isatty(fileno(stdout))) {
172 if (!freopen(
"/dev/null",
"w", stdout)) {
177 if (isatty(fileno(stderr))) {
178 if (!freopen(
"/dev/null",
"w", stderr)) {
184 static void rs_tv_add_ms(
struct timeval
const *start,
unsigned long interval,
struct timeval *result) {
185 result->tv_sec = start->tv_sec + (interval / 1000);
186 result->tv_usec = start->tv_usec + ((interval % 1000) * 1000);
188 if (result->tv_usec >
USEC) {
189 result->tv_usec -=
USEC;
206 ret = strftime(
out, len,
"%Y-%m-%d %H:%M:%S",
localtime_r(&t->tv_sec, &result));
214 while (usec < 100000) usec *= 10;
223 char const *start =
out;
238 while ((
inlen > 0) && (outlen > 2)) {
250 if ((*str ==
'\r') || (*str ==
'\n') || ((*str >=
'\x20') && (*str <=
'\x7E'))) {
277 len =
strlcpy(p,
"\"Status\",\"Count\",\"Time\",\"Latency\",\"Type\",\"Interface\","
278 "\"Src IP\",\"Src Port\",\"Dst IP\",\"Dst Port\",\"ID\",", s);
307 fprintf(stdout ,
"%s\n",
buffer);
312 UNUSED struct timeval *elapsed,
struct timeval *latency,
UNUSED bool response,
315 char const *status_str;
319 char src[INET6_ADDRSTRLEN];
320 char dst[INET6_ADDRSTRLEN];
332 (
unsigned int) latency->tv_sec,
333 ((
unsigned int) latency->tv_usec / 1000)) < 0)
return;
342 src, packet->
socket.inet.src_port, dst, packet->
socket.inet.dst_port, packet->
id) < 0)
return;
344 if (
fr_sbuff_in_sprintf(&sbuff,
"%u,%s,%s,%i,%s,%i,%i,", packet->
code, handle->name,
345 src, packet->
socket.inet.src_port, dst, packet->
socket.inet.dst_port, packet->
id) < 0)
return;
354 if (
vp && (
vp->vp_length > 0)) {
361 vp->vp_strvalue,
vp->vp_length);
362 if (slen < 0)
return;
378 fr_sbuff_terminate(&sbuff);
381 fprintf(stdout ,
"%s\n",
buffer);
386 struct timeval *elapsed,
struct timeval *latency,
bool response,
bool body)
391 char src[INET6_ADDRSTRLEN];
392 char dst[INET6_ADDRSTRLEN];
401 char const *status_str;
406 len =
snprintf(p, s,
"** %s ** ", status_str);
413 len =
snprintf(p, s,
"%s Id %i %s:%s:%d %s %s:%i ",
417 response ? dst : src,
418 response ? packet->
socket.inet.dst_port : packet->
socket.inet.src_port,
419 response ?
"<-" :
"->",
420 response ? src : dst ,
421 response ? packet->
socket.inet.src_port : packet->
socket.inet.dst_port);
423 len =
snprintf(p, s,
"%u Id %i %s:%s:%i %s %s:%i ",
427 response ? dst : src,
428 response ? packet->
socket.inet.dst_port : packet->
socket.inet.src_port,
429 response ?
"<-" :
"->",
430 response ? src : dst ,
431 response ? packet->
socket.inet.src_port : packet->
socket.inet.dst_port);
439 (
unsigned int) elapsed->tv_sec, ((
unsigned int) elapsed->tv_usec / 1000));
447 (
unsigned int) latency->tv_sec, ((
unsigned int) latency->tv_usec / 1000));
481 UNUSED struct timeval *elapsed,
UNUSED struct timeval *latency,
bool response,
bool body)
486 char const *packet_type = response ?
"reply" :
"request";
494 DEBUG2(
"Saving %s in %s", packet_type, filename);
501 ERROR(
"Failed opening %s output file.", filename);
519 ERROR(
"Failed closing %s output file.", filename);
532 struct timeval *elapsed,
struct timeval *latency,
533 bool response,
bool body)
537 if (request) request->
logged =
true;
538 conf->
logger(
count, status, handle, packet, list, elapsed, latency, response, body);
556 struct pcap_stat pstats;
558 if (pcap_stats(
in->handle, &pstats) != 0) {
559 ERROR(
"%s failed retrieving pcap stats: %s",
in->name, pcap_geterr(
in->handle));
563 if (pstats.ps_drop -
in->pstats.ps_drop > 0) {
564 ERROR(
"%s dropped %i packets: Buffer exhaustion",
in->name, pstats.ps_drop -
in->pstats.ps_drop);
568 if (pstats.ps_ifdrop -
in->pstats.ps_ifdrop > 0) {
569 ERROR(
"%s dropped %i packets: Interface",
in->name, pstats.ps_ifdrop -
in->pstats.ps_ifdrop);
591 if (
stats->interval.linked_total == 0) {
592 double unk = strtod(
"NAN()", (
char **) NULL);
594 stats->interval.latency_average = unk;
595 stats->interval.latency_high = unk;
596 stats->interval.latency_low = unk;
601 if (
stats->latency_smoothed_count == 0) {
602 stats->latency_smoothed = unk;
607 if (
stats->interval.linked_total &&
stats->interval.latency_total) {
608 stats->interval.latency_average = (
stats->interval.latency_total /
stats->interval.linked_total);
611 if (isnan((
long double)
stats->latency_smoothed)) {
612 stats->latency_smoothed = 0;
614 if (
stats->interval.latency_average > 0) {
615 stats->latency_smoothed_count++;
616 stats->latency_smoothed += ((
stats->interval.latency_average -
stats->latency_smoothed) /
617 ((
stats->latency_smoothed_count < 100) ?
stats->latency_smoothed_count : 100));
625 stats->interval.received = ((
long double)
stats->interval.received_total) /
conf->
stats.interval;
626 stats->interval.linked = ((
long double)
stats->interval.linked_total) /
conf->
stats.interval;
627 stats->interval.unlinked = ((
long double)
stats->interval.unlinked_total) /
conf->
stats.interval;
628 stats->interval.reused = ((
long double)
stats->interval.reused_total) /
conf->
stats.interval;
632 stats->interval.rt[i] = ((
long double)
stats->interval.rt_total[i]) /
conf->
stats.interval;
639 bool have_rt =
false;
643 if (!
stats->interval.received && !have_rt && !
stats->interval.reused)
return;
645 if (
stats->interval.received ||
stats->interval.linked) {
647 if (
stats->interval.received > 0) {
648 INFO(
"\tTotal : %.3lf/s" ,
stats->interval.received);
652 if (
stats->interval.linked > 0) {
653 INFO(
"\tLinked : %.3lf/s",
stats->interval.linked);
654 INFO(
"\tUnlinked : %.3lf/s",
stats->interval.unlinked);
656 INFO(
"\tHigh : %.3lfms",
stats->interval.latency_high);
657 INFO(
"\tLow : %.3lfms",
stats->interval.latency_low);
658 INFO(
"\tAverage : %.3lfms",
stats->interval.latency_average);
659 INFO(
"\tMA : %.3lfms",
stats->latency_smoothed);
666 if (
stats->interval.reused)
INFO(
"\tID Reused : %.3lf/s",
stats->interval.reused);
669 if (!
stats->interval.rt[i])
continue;
672 INFO(
"\tRT (%i) : %.3lf/s", i,
stats->interval.rt[i]);
674 INFO(
"\tRT (%i+) : %.3lf/s", i,
stats->interval.rt[i]);
692 if ((
stats->quiet.tv_sec + (
stats->quiet.tv_usec / 1000000.0)) -
693 (now->tv_sec + (now->tv_usec / 1000000.0)) > 0) {
694 INFO(
"Stats muted because of warmup, or previous error");
698 INFO(
"######### Stats Iteration %i #########",
stats->intervals);
700 if (this->
in)
INFO(
"Interface capture rate:");
701 for (in_p = this->
in;
704 struct pcap_stat pstats;
706 if (pcap_stats(in_p->handle, &pstats) != 0) {
707 ERROR(
"%s failed retrieving pcap stats: %s", in_p->name, pcap_geterr(in_p->handle));
711 INFO(
"\t%s%*s: %.3lf/s", in_p->name, (
int) (10 - strlen(in_p->name)),
"",
712 ((
double) (pstats.ps_recv - in_p->pstats.ps_recv)) /
conf->
stats.interval);
720 for (i = 0; i < rs_codes_len; i++) {
734 fprintf(stdout,
"\"Iteration\"");
736 for (in_p = this->
in; in_p; in_p = in_p->next) {
737 fprintf(stdout,
",\"%s PPS\"", in_p->name);
740 for (i = 0; i < rs_codes_len; i++) {
747 ",\"%s lat high (ms)\""
748 ",\"%s lat low (ms)\""
749 ",\"%s lat avg (ms)\""
750 ",\"%s lat ma (ms)\""
765 fprintf(stdout,
",\"%s rtx (%i)\"",
name, j);
767 fprintf(stdout,
",\"%s rtx (%i+)\"",
name, j);
772 fprintf(stdout ,
"\n");
778 char *p =
out, *end =
out + outlen;
780 p +=
snprintf(
out, outlen,
",%.3lf,%.3lf,%.3lf,%.3lf,%.3lf,%.3lf,%.3lf,%.3lf,%.3lf",
781 stats->interval.received,
782 stats->interval.linked,
783 stats->interval.unlinked,
784 stats->interval.latency_high,
785 stats->interval.latency_low,
786 stats->interval.latency_average,
787 stats->latency_smoothed,
789 stats->interval.reused);
790 if (p >= end)
return -1;
794 if (p >= end)
return -1;
810 ERROR(
"Exceeded line buffer size");
814 for (in_p = this->
in;
817 struct pcap_stat pstats;
819 if (pcap_stats(in_p->handle, &pstats) != 0) {
820 ERROR(
"%s failed retrieving pcap stats: %s", in_p->name, pcap_geterr(in_p->handle));
825 ((
double) (pstats.ps_recv - in_p->pstats.ps_recv)) /
conf->
stats.interval);
826 if (p >= end)
goto oob;
829 for (i = 0; i < rs_codes_len; i++) {
833 if (slen < 0)
goto oob;
836 if (p >= end)
goto oob;
839 fprintf(stdout ,
"%s\n",
buffer);
856 if (!this->done_header) {
858 this->done_header =
true;
863 for (in_p = this->
in;
867 ERROR(
"Muting stats for the next %i milliseconds",
conf->
stats.timeout);
877 if ((
stats->quiet.tv_sec + (
stats->quiet.tv_usec / 1000000.0)) -
878 (now.tv_sec + (now.tv_usec / 1000000.0)) > 0)
goto clear;
880 for (i = 0; i < rs_codes_len; i++) {
885 if (this->body) this->body(
this,
stats, &now);
887 #ifdef HAVE_COLLECTDC_H
901 for (i = 0; i < rs_codes_len; i++) {
914 ERROR(
"Failed inserting stats interval event");
927 stats->interval.linked_total++;
929 lint = (latency->tv_sec + (latency->tv_usec / 1000000.0)) * 1000;
930 if (lint >
stats->interval.latency_high) {
931 stats->interval.latency_high = lint;
933 if (!
stats->interval.latency_low || (lint < stats->interval.latency_low)) {
934 stats->interval.latency_low = lint;
936 stats->interval.latency_total += (
long double) lint;
941 fr_pcap_t *
in,
struct timeval *now,
bool live)
946 memset(&update, 0,
sizeof(update));
964 #ifdef HAVE_COLLECTDC_H
965 case RS_STATS_OUT_COLLECTD:
978 INFO(
"Muting stats for the next %i milliseconds (warmup)",
conf->
stats.timeout);
984 ERROR(
"Failed inserting stats event");
1006 for (i = 0; i < num; i++) {
1047 if (request->
event) {
1106 if ((request->
in->type == PCAP_INTERFACE_IN) && request->
logged) {
1137 request->
event = NULL;
1155 if (!event->
out)
return 0;
1197 pcap_dump((
void *)event->
out->dumper, header,
data);
1205 if (!event->
out)
return 0;
1217 if (!(request->
capture_p->
header = talloc(request,
struct pcap_pkthdr)))
return -1;
1222 memcpy(request->
capture_p->
header, header,
sizeof(
struct pcap_pkthdr));
1234 pcap_dump((
void *)event->
out->dumper, header,
data);
1240 #define RS_CLEANUP_NOW(_x, _s)\
1242 _x->silent_cleanup = _s;\
1243 _x->when = header->ts;\
1244 rs_packet_cleanup(_x);\
1267 struct timeval elapsed = {0, 0};
1268 struct timeval latency;
1283 static uint64_t captured = 0;
1294 memset(&search, 0,
sizeof(search));
1307 len = fr_pcap_link_layer_offset(
data, header->caplen, event->
in->link_layer);
1309 REDEBUG(
"Failed determining link layer header offset");
1314 version = (p[0] & 0xf0) >> 4;
1318 len = (0x0f & ip->
ip_vhl) * 4;
1329 REDEBUG(
"IP version invalid %i", version);
1337 if ((
size_t) len > header->caplen) {
1338 REDEBUG(
"Packet too small, we require at least %zu bytes, captured %i bytes",
1339 (
size_t) len, header->caplen);
1351 udp_len = ntohs(udp->
len);
1352 actual_len = header->caplen - (p -
data);
1354 if (udp_len > actual_len) {
1355 REDEBUG(
"Packet too small by %zi bytes, UDP header + Payload should be %hu bytes",
1356 udp_len - actual_len, udp_len);
1369 else if (udp_len < actual_len) {
1370 REDEBUG(
"Packet too big by %zi bytes, UDP header + Payload should be %hu bytes",
1371 actual_len - udp_len, udp_len);
1380 if (udp->checksum != expected) {
1381 REDEBUG(
"UDP checksum invalid, packet: 0x%04hx calculated: 0x%04hx",
1382 ntohs(udp->checksum), ntohs(expected));
1396 REDEBUG(
"Failed allocating memory to hold decoded packet");
1403 memcpy(&packet->
data, &p,
sizeof(packet->
data));
1411 packet->
socket.inet.src_ipaddr.
af = AF_INET;
1412 packet->
socket.inet.src_ipaddr.addr.v4.s_addr = ip->ip_src.s_addr;
1414 packet->
socket.inet.dst_ipaddr.
af = AF_INET;
1415 packet->
socket.inet.dst_ipaddr.addr.v4.s_addr = ip->
ip_dst.s_addr;
1417 packet->
socket.inet.src_ipaddr.
af = AF_INET6;
1418 memcpy(packet->
socket.inet.src_ipaddr.addr.v6.s6_addr, ip6->ip_src.s6_addr,
1419 sizeof(packet->
socket.inet.src_ipaddr.addr.v6.s6_addr));
1421 packet->
socket.inet.dst_ipaddr.
af = AF_INET6;
1422 memcpy(packet->
socket.inet.dst_ipaddr.addr.v6.s6_addr, ip6->
ip_dst.s6_addr,
1423 sizeof(packet->
socket.inet.dst_ipaddr.addr.v6.s6_addr));
1426 packet->
socket.inet.src_port = ntohs(udp->
src);
1427 packet->
socket.inet.dst_port = ntohs(udp->
dst);
1433 packet, &decoded, &elapsed, NULL,
false,
false);
1440 switch (packet->
code) {
1460 RDEBUG2(
"Response dropped by filter");
1478 fr_perror(
"Failed verifying packet ID %d", packet->
id);
1546 original->
linked = talloc_steal(original, packet);
1551 REDEBUG(
"Failed inserting new event");
1570 RDEBUG2(
"Original request dropped by filter");
1575 stats->exchange[packet->
code].interval.unlinked_total++;
1595 RDEBUG2(
"Request dropped by filter");
1602 switch (packet->
code) {
1614 fr_perror(
"Failed verifying packet ID %d", packet->
id);
1655 REDEBUG(
"Failed allocating memory to hold expected reply");
1669 ERROR(
"Failed extracting RTX linking pairs from request");
1689 if (tuple && (original != tuple)) {
1704 stats->exchange[packet->
code].interval.reused_total++;
1741 original->
packet = talloc_steal(original, packet);
1752 original->
expect = talloc_steal(original, search.
expect);
1763 original->
in =
event->in;
1769 original->
packet = talloc_steal(original, packet);
1772 original->
expect = talloc_steal(original, search.
expect);
1819 REDEBUG(
"Failed inserting new event");
1841 stats->exchange[packet->
code].interval.received_total++;
1846 if (original && original->
linked) {
1865 struct timeval ts_tv;
1880 &elapsed, &latency, response,
true);
1893 print_id = original->
id;
1899 print_pair_list = &decoded;
1904 &elapsed, NULL, response,
true);
1913 if (response && !original) {
1922 INFO(
"Captured %" PRIu64
" packets, exiting...", captured);
1929 static uint64_t
count = 0;
1933 pcap_t *handle =
event->in->handle;
1938 struct pcap_pkthdr *header;
1949 last_sync = now_real;
1955 if ((event->in->type == PCAP_FILE_IN) || (event->in->type == PCAP_STDIO_IN)) {
1956 bool stats_started =
false;
1961 ret = pcap_next_ex(handle, &header, &
data);
1967 DEBUG(
"Done reading packets (%s)", event->in->name);
1977 ERROR(
"Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
1985 if (
conf->
stats.interval && !stats_started) {
1987 stats_started =
true;
2005 ret = pcap_next_ex(handle, &header, &
data);
2011 ERROR(
"Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
2022 struct timeval wake;
2026 if ((wake.tv_sec != 0) || (wake.tv_usec >= 100000)) {
2027 DEBUG2(
"Waking up in %d.%01u seconds", (
int) wake.tv_sec, (
unsigned int) wake.tv_usec / 100000);
2053 if (ret != 0)
return ret;
2056 if (ret != 0)
return ret;
2068 while ((tok =
strsep(&p,
"\t ,")) != NULL) {
2070 if ((*tok ==
'\t') || (*tok ==
' ') || (*tok ==
'\0')) {
2075 ERROR(
"Too many attributes, maximum allowed is %zu", len);
2082 ERROR(
"Error parsing attribute name \"%s\"", tok);
2106 .allow_compare =
true,
2111 fr_perror(
"Invalid RADIUS filter \"%s\"", filter);
2116 ERROR(
"Empty RADIUS filter '%s'", filter);
2134 while ((tok =
strsep(&p,
"\t ,")) != NULL) {
2137 if ((*tok ==
'\t') || (*tok ==
' ') || (*tok ==
'\0')) {
2143 ERROR(
"Invalid flag \"%s\"", tok);
2160 this->in_request_tree =
false;
2170 this->in_link_tree =
false;
2182 #ifdef HAVE_COLLECTDC_H
2190 if (rs_stats_collectd_open(
conf) == 0) {
2191 DEBUG2(
"Stats output socket (re)opened");
2199 rs_collectd_reopen,
el) < 0) {
2200 ERROR(
"Failed inserting re-open event");
2212 if (write(
self_pipe[1], &sig,
sizeof(sig)) < 0) {
2213 ERROR(
"Failed writing signal %s to pipe: %s", strsignal(sig),
fr_syserror(errno));
2222 #ifndef HAVE_COLLECTDC_H
2230 ret = read(fd, &sig,
sizeof(sig));
2236 if (ret !=
sizeof(sig)) {
2237 ERROR(
"Failed reading signal from pipe: "
2238 "Expected signal to be %zu bytes but only read %zu byes",
sizeof(sig), ret);
2243 #ifdef HAVE_COLLECTDC_H
2245 rs_collectd_reopen(list,
fr_time(), list);
2254 DEBUG2(
"Signalling event loop to exit");
2259 ERROR(
"Unhandled signal %s", strsignal(sig));
2266 FILE *output = status ? stderr : stdout;
2267 fprintf(output,
"Usage: radsniff [options][stats options] -- [pcap files]\n");
2268 fprintf(output,
"options:\n");
2269 fprintf(output,
" -a List all interfaces available for capture.\n");
2270 fprintf(output,
" -c <count> Number of packets to capture.\n");
2271 fprintf(output,
" -C <checksum_type> Enable checksum validation. (Specify 'udp' or 'radius')\n");
2272 fprintf(output,
" -d <raddb> Set configuration directory (defaults to " RADDBDIR
").\n");
2273 fprintf(output,
" -D <dictdir> Set main dictionary directory (defaults to " DICTDIR
").\n");
2274 fprintf(output,
" -e <event>[,<event>] Only log requests with these event flags.\n");
2275 fprintf(output,
" Event may be one of the following:\n");
2276 fprintf(output,
" - received - a request or response.\n");
2277 fprintf(output,
" - norsp - seen for a request.\n");
2278 fprintf(output,
" - rtx - of a request that we've seen before.\n");
2279 fprintf(output,
" - noreq - could be matched with the response.\n");
2280 fprintf(output,
" - reused - ID too soon.\n");
2281 fprintf(output,
" - error - decoding the packet.\n");
2282 fprintf(output,
" -f <filter> PCAP filter (default is 'udp port <port> or <port + 1> or %i'\n",
2284 fprintf(output,
" with extra rules to allow .1Q tagged packets)\n");
2285 fprintf(output,
" -h This help message.\n");
2286 fprintf(output,
" -i <interface> Capture packets from interface (defaults to all if supported).\n");
2287 fprintf(output,
" -I <file> Read packets from <file>\n");
2288 fprintf(output,
" -l <attr>[,<attr>] Output packet sig and a list of attributes.\n");
2289 fprintf(output,
" -L <attr>[,<attr>] Detect retransmissions using these attributes to link requests.\n");
2290 fprintf(output,
" -m Don't put interface(s) into promiscuous mode.\n");
2291 fprintf(output,
" -p <port> Filter packets by port (default is %i).\n",
FR_AUTH_UDP_PORT);
2292 fprintf(output,
" -P <pidfile> Daemonize and write out <pidfile>.\n");
2293 fprintf(output,
" -q Print less debugging information.\n");
2294 fprintf(output,
" -r <filter> RADIUS attribute request filter.\n");
2295 fprintf(output,
" -R <filter> RADIUS attribute response filter.\n");
2296 fprintf(output,
" -s <secret> RADIUS secret.\n");
2297 fprintf(output,
" -S Write PCAP data to stdout.\n");
2298 fprintf(output,
" -t <timeout> Stop after <timeout> seconds.\n");
2299 fprintf(output,
" -v Show program version information and exit.\n");
2300 fprintf(output,
" -w <file> Write output packets to file.\n");
2301 fprintf(output,
" -x Print more debugging information.\n");
2302 fprintf(output,
"stats options:\n");
2303 fprintf(output,
" -W <interval> Periodically write out statistics every <interval> seconds.\n");
2304 fprintf(output,
" -E Print stats in CSV format.\n");
2305 fprintf(output,
" -T <timeout> How many milliseconds before the request is counted as lost "
2307 #ifdef HAVE_COLLECTDC_H
2308 fprintf(output,
" -N <prefix> The instance name passed to the collectd plugin.\n");
2309 fprintf(output,
" -O <server> Write statistics to this collectd server.\n");
2311 fprintf(output,
" -Z <output_dir> Dump the packets in <output_dir>/{requests,reply}.${count}.txt\n");
2321 fr_pcap_t *
in = NULL, *in_p;
2322 fr_pcap_t **in_head = &
in;
2323 fr_pcap_t *
out = NULL;
2325 int ret = EXIT_SUCCESS;
2327 char errbuf[PCAP_ERRBUF_SIZE];
2333 char const *raddb_dir = RADDBDIR;
2334 char const *dict_dir = DICTDIR;
2359 talloc_set_log_stderr();
2374 #ifdef HAVE_COLLECTDC_H
2380 #ifdef HAVE_COLLECTDC_H
2387 while ((c = getopt(argc, argv,
"ab:c:C:d:D:e:Ef:hi:I:l:L:mp:P:qr:R:s:St:vw:xXW:T:P:N:O:Z:")) != -1) {
2391 pcap_if_t *all_devices = NULL;
2395 if (pcap_findalldevs(&all_devices, errbuf) < 0) {
2396 ERROR(
"Error getting available capture devices: %s", errbuf);
2401 for (dev_p = all_devices;
2403 dev_p = dev_p->next) {
2404 INFO(
"%i.%s", i++, dev_p->name);
2407 pcap_freealldevs(all_devices);
2415 ERROR(
"Invalid buffer length \"%s\"", optarg);
2423 ERROR(
"Invalid number of packets \"%s\"", optarg);
2430 if (strcmp(optarg,
"udp") == 0) {
2433 }
else if (strcmp(optarg,
"radius") == 0) {
2437 ERROR(
"Must specify 'udp' or 'radius' for -C, not %s", optarg);
2467 *in_head = fr_pcap_init(
conf, optarg, PCAP_INTERFACE_IN);
2468 if (!*in_head)
goto finish;
2469 in_head = &(*in_head)->next;
2474 *in_head = fr_pcap_init(
conf, optarg, PCAP_FILE_IN);
2478 in_head = &(*in_head)->next;
2495 port = atoi(optarg);
2531 #ifdef HAVE_COLLECTDC_H
2533 lcc_version_string());
2540 out = fr_pcap_init(
conf, optarg, PCAP_FILE_OUT);
2542 ERROR(
"Failed creating pcap file \"%s\"", optarg);
2557 ERROR(
"Stats interval must be > 0");
2565 size_t len = strlen(p);
2570 if (p[len-1] ==
'/') p[len-1] =
'\0';
2584 ERROR(
"Timeout value must be > 0");
2589 #ifdef HAVE_COLLECTDC_H
2596 conf->
stats.out = RS_STATS_OUT_COLLECTD;
2613 while (optind < argc) {
2614 *in_head = fr_pcap_init(
conf, argv[optind], PCAP_FILE_IN);
2618 in_head = &(*in_head)->next;
2624 if (!isatty(fileno(stdin))) {
2635 ERROR(
"Can't read from both a file and a device");
2641 ERROR(
"CSV output requires a statistics interval (-W)");
2656 out = fr_pcap_init(
conf,
"stdout", PCAP_STDIO_OUT);
2663 *in_head = fr_pcap_init(
conf,
"stdin", PCAP_STDIO_IN);
2667 in_head = &(*in_head)->next;
2695 #if !defined(HAVE_PCAP_FOPEN_OFFLINE) || !defined(HAVE_PCAP_DUMP_FOPEN)
2697 ERROR(
"PCAP streams not supported");
2763 ERROR(
"Failed creating RTX tree");
2800 DEBUG(
"Logging all events");
2821 ERROR(
"Failed creating request tree");
2829 pcap_if_t *all_devices;
2832 if (pcap_findalldevs(&all_devices, errbuf) < 0) {
2833 ERROR(
"Error getting available capture devices: %s", errbuf);
2838 ERROR(
"No capture files specified and no live interfaces available");
2840 pcap_freealldevs(all_devices);
2844 for (dev_p = all_devices;
2846 dev_p = dev_p->next) {
2850 if (!strcmp(dev_p->name,
"any"))
continue;
2853 if (!strncmp(dev_p->name,
"pktap", 5))
continue;
2855 link_layer = fr_pcap_if_link_layer(dev_p);
2856 if (link_layer < 0) {
2861 if (!fr_pcap_link_layer_supported(link_layer)) {
2862 DEBUG2(
"Skipping %s: datalink type %s not supported",
2863 dev_p->name, pcap_datalink_val_to_name(link_layer));
2867 *in_head = fr_pcap_init(
conf, dev_p->name, PCAP_INTERFACE_IN);
2868 in_head = &(*in_head)->next;
2870 pcap_freealldevs(all_devices);
2874 INFO(
"Defaulting to capture on all interfaces");
2881 DEBUG2(
"Sniffing with options:");
2883 char *
buff = fr_pcap_device_names(
conf,
in,
' ');
2888 DEBUG2(
" Writing to : [%s]",
out->name);
2901 DEBUG2(
" RADIUS request filter :");
2914 DEBUG2(
" RADIUS response filter :");
2922 #ifdef HAVE_COLLECTDC_H
2923 if (
conf->
stats.out == RS_STATS_OUT_COLLECTD) {
2925 rs_stats_tmpl_t *tmpl, **next;
2927 if (rs_stats_collectd_open(
conf) < 0) {
2934 tmpl = rs_stats_collectd_init_latency(
conf, next,
conf,
"exchanged",
2938 ERROR(
"Error allocating memory for stats template");
2941 next = &(tmpl->next);
2951 fr_pcap_t **tmp_p = &tmp;
2955 in_p = in_p->next) {
2958 if (fr_pcap_open(in_p) < 0) {
2959 fr_perror(
"Failed opening pcap handle (%s)", in_p->name);
2967 if (!fr_pcap_link_layer_supported(in_p->link_layer)) {
2968 ERROR(
"Failed opening pcap handle (%s): Datalink type %s not supported",
2969 in_p->name, pcap_datalink_val_to_name(in_p->link_layer));
2988 tmp_p = &(in_p->next);
2994 ERROR(
"No PCAP sources available");
3006 out->link_layer = -1;
3010 in_p = in_p->next) {
3011 if (
out->link_layer < 0) {
3012 out->link_layer = in_p->link_layer;
3016 if (
out->link_layer != in_p->link_layer) {
3017 ERROR(
"Asked to write to output file, but inputs do not have the same link type");
3025 if (fr_pcap_open(
out) < 0) {
3026 fr_perror(
"Failed opening pcap output (%s)",
out->name);
3063 fr_perror(
"Failed inserting signal pipe descriptor");
3083 in_p = in_p->next) {
3090 event->stats =
stats;
3103 if (event->
in->type == PCAP_FILE_IN) {
3110 ERROR(
"Failed inserting file descriptor");
3118 ERROR(
"Failed inserting timeout event");
3145 DEBUG2(
"Entering event loop");
static int const char char buffer[256]
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
#define fr_base16_encode(_out, _in)
#define NEVER_RETURNS
Should be placed before the function return type.
#define L(_str)
Helper for initialising arrays of string literals.
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static void * fr_dcursor_remove(fr_dcursor_t *cursor)
Remove the current item.
static void * fr_dcursor_filter_next(fr_dcursor_t *cursor, fr_dcursor_eval_t eval, void const *uctx)
Return the next item, skipping the current item, that satisfies an evaluation function.
static void * fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
Set the cursor to a specified item.
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
fr_radius_packet_code_t
RADIUS packet codes.
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
@ FR_RADIUS_CODE_DISCONNECT_REQUEST
RFC3575/RFC5176 - Disconnect-Request.
@ FR_RADIUS_CODE_DISCONNECT_ACK
RFC3575/RFC5176 - Disconnect-Ack (positive)
@ FR_RADIUS_CODE_STATUS_SERVER
RFC2865/RFC5997 - Status Server (request)
@ FR_RADIUS_CODE_COA_REQUEST
RFC3575/RFC5176 - CoA-Request.
@ FR_RADIUS_CODE_STATUS_CLIENT
RFC2865/RFC5997 - Status Server (response)
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
@ FR_RADIUS_CODE_ACCOUNTING_RESPONSE
RFC2866 - Accounting-Response.
@ FR_RADIUS_CODE_COA_NAK
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
@ FR_RADIUS_CODE_COA_ACK
RFC3575/RFC5176 - CoA-Ack (positive)
@ FR_RADIUS_CODE_DISCONNECT_NAK
RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
@ FR_RADIUS_CODE_ACCOUNTING_REQUEST
RFC2866 - Accounting-Request.
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
static fr_time_delta_t timeout
#define fr_dict_autofree(_to_free)
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
#define fr_dict_autoload(_to_load)
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename)
Read supplementary attribute definitions into an existing dictionary.
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
Initialise the global protocol hashes.
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define fr_event_fd_insert(...)
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
#define fr_event_timer_at(...)
#define fr_event_timer_in(...)
ssize_t fr_mkdir(int *fd_out, char const *path, ssize_t len, mode_t mode, fr_mkdir_func_t func, void *uctx)
Create directories that are missing in the specified path.
int fr_unlink(char const *filename)
Remove a regular file from the filesystem.
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
uint64_t fr_event_list_num_fds(fr_event_list_t *el)
Return the number of file descriptors is_registered with this event loop.
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
bool fr_event_loop_exiting(fr_event_list_t *el)
Check to see whether the event loop is in the process of exiting.
int fr_event_timer_run(fr_event_list_t *el, fr_time_t *when)
Run a single scheduled timer event.
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Stores all information relating to an event list.
int fr_log_init_file(fr_log_t *log, char const *file)
Initialise a file logging destination.
int fr_log_close(fr_log_t *log)
Universal close function for all logging destinations.
@ L_TIMESTAMP_OFF
Never log timestamps.
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
@ L_DBG_LVL_4
4th highest priority debug messages (-xxxx | -Xxx).
fr_packet_t * fr_packet_alloc_reply(TALLOC_CTX *ctx, fr_packet_t *packet)
Allocate a new fr_packet_t response.
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
void fr_packet_free(fr_packet_t **packet_p)
Free a fr_packet_t.
int8_t fr_packet_cmp(void const *a_v, void const *b_v)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
void fr_quick_sort(void const *to_sort[], int start, int end, fr_cmp_t cmp)
Quick sort an array of pointers using a comparator.
int fr_set_signal(int sig, sig_t func)
Sets a signal handler using sigaction if available, else signal.
int8_t fr_pointer_cmp(void const *a, void const *b)
Compares two pointers.
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
char * strsep(char **stringp, char const *delim)
uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum, struct in_addr const src_addr, struct in_addr const dst_addr)
Calculate UDP checksum.
struct in6_addr ip_src ip_dst
Src and Dst address.
#define RADIUS_AUTH_VECTOR_LENGTH
uint16_t dst
Destination port.
uint16_t checksum
UDP checksum.
struct in_addr ip_src ip_dst
Src and Dst address.
uint8_t ip_vhl
Header length, version.
bool fr_pair_matches_da(void const *item, void const *uctx)
Evaluation function for matching if vp matches a given da.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_list_cmp(fr_pair_list_t const *a, fr_pair_list_t const *b)
Determine equality of two lists.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
int fr_pair_steal(TALLOC_CTX *ctx, fr_pair_t *vp)
Steal one VP.
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
bool fr_pair_validate_relaxed(fr_pair_t const *failed[2], fr_pair_list_t *filter, fr_pair_list_t *list)
Uses fr_pair_cmp to verify all fr_pair_ts in list match the filter defined by check.
int8_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da, and tag.
fr_slen_t fr_pair_list_afrom_substr(fr_pair_parse_t const *root, fr_pair_parse_t *relative, fr_sbuff_t *in)
Parse a fr_pair_list_t from a substring.
struct fr_pair_parse_s fr_pair_parse_t
int fr_radius_global_init(void)
ssize_t fr_radius_decode_simple(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t *packet, size_t packet_len, uint8_t const *vector, char const *secret)
Simple wrapper for callers who just need a shared secret.
void fr_radius_global_free(void)
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
bool fr_packet_ok(fr_packet_t *packet, uint32_t max_attributes, bool require_ma, decode_fail_t *reason)
See if the data pointed to by PTR is a valid RADIUS packet.
int fr_packet_verify(fr_packet_t *packet, fr_packet_t *original, char const *secret)
Verify the Request/Response Authenticator (and Message-Authenticator if present) of a packet.
static TALLOC_CTX * autofree
uint64_t lost
Requests to which we received no response.
#define RADIUS_MAX_ATTRIBUTES
#define fr_packet_log_hex(_log, _packet)
#define FR_RADIUS_PACKET_CODE_VALID(_x)
fr_dict_attr_autoload_t radsniff_dict_attr[]
static void rs_stats_process(fr_event_list_t *el, fr_time_t now_t, void *ctx)
Process stats for a single interval.
static int rs_request_to_pcap(rs_event_t *event, rs_request_t *request, struct pcap_pkthdr const *header, uint8_t const *data)
static rs_request_t * rs_request_alloc(TALLOC_CTX *ctx)
static struct timeval start_pcap
static size_t rs_snprint_csv(char *out, size_t outlen, char const *in, size_t inlen)
static fr_rb_tree_t * link_tree
static void rs_packet_print(rs_request_t *request, uint64_t count, rs_status_t status, fr_pcap_t *handle, fr_packet_t *packet, fr_pair_list_t *list, struct timeval *elapsed, struct timeval *latency, bool response, bool body)
static int self_pipe[2]
Signals from sig handlers.
int main(int argc, char *argv[])
static fr_dict_attr_t const * attr_packet_type
static void rs_stats_process_latency(rs_latency_t *stats)
Update smoothed average.
static ssize_t rs_stats_print_code_csv(char *out, size_t outlen, rs_latency_t *stats)
static void rs_stats_print_code_fancy(rs_latency_t *stats, fr_radius_packet_code_t code)
static void rs_daemonize(char const *pidfile)
Fork and kill the parent process, writing out our PID.
static int rs_install_stats_processor(rs_stats_t *stats, fr_event_list_t *el, fr_pcap_t *in, struct timeval *now, bool live)
static fr_event_list_t * events
static const uint8_t zeros[RADIUS_AUTH_VECTOR_LENGTH]
static void rs_packet_save_in_output_dir(uint64_t count, UNUSED rs_status_t status, UNUSED fr_pcap_t *handle, fr_packet_t *packet, fr_pair_list_t *list, UNUSED struct timeval *elapsed, UNUSED struct timeval *latency, bool response, bool body)
static void rs_packet_print_csv_header(void)
static fr_dict_t const * dict_freeradius
static int rs_response_to_pcap(rs_event_t *event, rs_request_t *request, struct pcap_pkthdr const *header, uint8_t const *data)
static fr_rb_tree_t * request_tree
static fr_dict_t const * dict_radius
static int _rs_event_status(UNUSED fr_time_t now, fr_time_delta_t wake_t, UNUSED void *uctx)
static char const * radsniff_version
static void _unmark_request(void *request)
Callback for when the request is removed from the request tree.
static int rs_build_event_flags(int *flags, fr_table_num_sorted_t const *map, size_t map_len, char *list)
static int8_t rs_rtx_cmp(void const *one, void const *two)
Compare requests using packet info and lists of attributes.
static void rs_stats_print_csv(rs_update_t *this, rs_stats_t *stats, UNUSED struct timeval *now)
static int rs_check_pcap_drop(fr_pcap_t *in)
Query libpcap to see if it dropped any packets.
static void rs_stats_print_fancy(rs_update_t *this, rs_stats_t *stats, struct timeval *now)
static size_t rs_events_len
static int rs_build_dict_list(fr_dict_attr_t const **out, size_t len, char *list)
fr_dict_autoload_t radsniff_dict[]
static void rs_tv_add_ms(struct timeval const *start, unsigned long interval, struct timeval *result)
static void rs_time_print(char *out, size_t len, struct timeval const *t)
static void rs_signal_self(int sig)
Write the last signal to the signal pipe.
static void rs_packet_cleanup(rs_request_t *request)
static void _rs_event(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx)
static void _unmark_link(void *request)
Callback for when the request is removed from the link tree.
static void rs_stats_print_csv_header(rs_update_t *this)
#define RS_CLEANUP_NOW(_x, _s)
static void rs_got_packet(fr_event_list_t *el, int fd, UNUSED int flags, void *ctx)
static void rs_packet_print_fancy(uint64_t count, rs_status_t status, fr_pcap_t *handle, fr_packet_t *packet, fr_pair_list_t *list, struct timeval *elapsed, struct timeval *latency, bool response, bool body)
static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkthdr const *header, uint8_t const *data)
static int8_t rs_packet_cmp(void const *one, void const *two)
Wrapper around fr_packet_cmp to strip off the outer request struct.
static int rs_get_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_pair_list_t *vps, fr_dict_attr_t const *da[], int num)
Copy a subset of attributes from one list into the other.
static void rs_signal_action(UNUSED fr_event_list_t *list, int fd, int UNUSED flags, UNUSED void *ctx)
Read the last signal from the signal pipe.
static NEVER_RETURNS void usage(int status)
static void rs_packet_print_csv(uint64_t count, rs_status_t status, fr_pcap_t *handle, fr_packet_t *packet, fr_pair_list_t *list, UNUSED struct timeval *elapsed, struct timeval *latency, UNUSED bool response, bool body)
static void rs_stats_process_counters(rs_latency_t *stats)
static int rs_useful_codes[]
static int _request_free(rs_request_t *request)
static void rs_stats_update_latency(rs_latency_t *stats, struct timeval *latency)
Update latency statistics for request/response and forwarded packets.
static int rs_build_filter(fr_pair_list_t *out, char const *filter)
static void timeout_event(fr_event_list_t *el, UNUSED fr_time_t now_t, UNUSED void *ctx)
Exit the event loop after a given timeout.
static fr_table_num_sorted_t const rs_events[]
Structures and prototypes for the RADIUS sniffer.
fr_radius_packet_code_t filter_response_code
Filter response packets by code.
fr_pcap_t * in
PCAP handle event occurred on.
fr_packet_t * expect
Request/response.
bool to_output_dir
Were writing attributes into directory.
fr_event_timer_t const * event
Event created when we received the original request.
rs_stats_print_cb_t body
Print body.
bool print_packet
Print packet info, disabled with -W.
uint8_t * data
PCAP packet data.
fr_dict_attr_t const * list_da[RS_MAX_ATTRS]
Output CSV with these attribute values.
char const * output_dir
Where we should save the files $PATH/requests.txt and $PATH/reply.txt.
@ RS_STATS_OUT_STDIO_FANCY
#define RS_DEFAULT_SECRET
Default secret.
bool in_request_tree
Whether the request is currently in the request tree.
rs_status_t event_flags
Events we log and capture on.
fr_dict_attr_t const * link_da[RS_MAX_ATTRS]
fr_dict_attr_ts to link on.
int link_da_num
Number of rtx fr_dict_attr_ts.
fr_radius_packet_code_t filter_request_code
Filter request packets by code.
rs_stats_t * stats
Stats to process.
int buffer_pkts
Size of the ring buffer to setup for live capture.
char const * filter_response
Raw response filter string.
fr_event_list_t * list
List to insert new event into.
struct timeval when
Time when the packet was received, or next time an event is scheduled.
bool from_dev
Were reading pcap data from devices.
#define RS_FORCE_YIELD
Service another descriptor every X number of packets.
#define RS_DEFAULT_TIMEOUT
Standard timeout of 5s + 300ms to cover network latency.
rs_packet_logger_t logger
Packet logger.
char * pcap_filter_vlan
Variant of the normal filter to apply to devices which support VLAN tags.
char * pcap_filter
PCAP filter string applied to live capture devices.
rs_capture_t capture[RS_RETRANSMIT_MAX]
Buffered request packets (if a response filter has been applied).
bool from_auto
From list was auto-generated.
rs_latency_t * stats_req
Latency entry for the request type.
bool decode_attrs
Whether we should decode attributes in the request and response.
uint64_t id
Monotonically increasing packet counter.
rs_latency_t * stats_rsp
Latency entry for the request type.
bool to_file
Were writing pcap data to files.
fr_pair_list_t link_vps
fr_pair_ts used to link retransmissions.
fr_packet_t * packet
The original packet.
#define RS_RETRANSMIT_MAX
Maximum number of times we expect to see a packet retransmitted.
rs_stats_print_header_cb_t head
Print header.
char * list_attributes
Raw attribute filter string.
char * radius_secret
Secret to decode encrypted attributes.
bool from_file
Were reading pcap data from files.
fr_pcap_t * out
Where to write output.
#define RS_DEFAULT_PREFIX
Default instance.
fr_pcap_t * in
PCAP handle the original request was received on.
fr_pcap_t * in
Linked list of PCAP handles to check for drops.
rs_capture_t * capture_p
Next packet slot.
bool in_link_tree
Whether the request is currently in the linked tree.
#define RIDEBUG_ENABLED()
fr_event_list_t * list
The event list.
fr_packet_t * linked
The subsequent response or forwarded request the packet.
bool verify_radius_authenticator
Check RADIUS authenticator in packets.
uint64_t limit
Maximum number of packets to capture.
char const * pidfile
File to write PID to.
uint64_t rt_rsp
Number of times we saw a retransmitted response packet.
bool from_stdin
Were reading pcap data from stdin.
bool daemonize
Daemonize and write PID out to file.
uint64_t rt_req
Number of times we saw the same request packet.
fr_pair_list_t filter_response_vps
Sorted filter vps.
bool promiscuous
Capture in promiscuous mode.
fr_pair_list_t expect_vps
fr_pair_list_t packet_vps
bool logged
Whether any messages regarding this request were logged.
char * link_attributes
Names of fr_dict_attr_ts to use for rtx.
bool silent_cleanup
Cleanup was forced before normal expiry period, ignore stats about packet loss.
char const * filter_request
Raw request filter string.
struct pcap_pkthdr * header
PCAP packet header.
#define RS_SOCKET_REOPEN_DELAY
How long we delay re-opening a collectd socket.
bool verify_udp_checksum
Check UDP checksum in packets.
bool to_stdout
Were writing pcap data to stdout.
struct rs_latency_t::@0 interval
fr_pair_list_t filter_request_vps
Sorted filter vps.
Statistic write/print event.
Stats for a single interval.
FD data which gets passed to callbacks.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
The main red black tree structure.
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_in_char(_sbuff,...)
static char buff[sizeof("18446744073709551615")+3]
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
fr_aka_sim_id_type_t type
#define fr_time()
Allow us to arbitrarily manipulate time.
size_t strlcpy(char *dst, char const *src, size_t siz)
fr_log_timestamp_t timestamp
Prefix log messages with timestamps.
bool print_level
sometimes we don't want log levels printed
FILE * handle
Path to log file.
Stores an attribute, a value and various bits of other data.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
int fr_time_sync(void)
Get a new fr_time_monotonic_to_realtime value.
int fr_time_start(void)
Initialize the local time.
static fr_time_t fr_time_from_timeval(struct timeval const *when_tv)
Convert a timeval (wallclock time) to a fr_time_t (internal time)
static fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_wrap(_time)
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
#define fr_time_add(_a, _b)
Add a time/time delta together.
#define fr_time_to_timeval(_when)
Convert server epoch time to unix epoch time.
#define fr_time_sub(_a, _b)
Subtract one time from another.
#define fr_time_delta_gt(_a, _b)
A time delta, a difference in time measured in nanoseconds.
void fr_timeval_subtract(struct timeval *out, struct timeval const *end, struct timeval const *start)
Subtract one timeval from another.
static fr_event_list_t * el
static void print_packet(FILE *fp, fr_packet_t *packet, fr_pair_list_t *list)
#define FR_DICTIONARY_FILE
unsigned int code
Packet code (type).
fr_socket_t socket
This packet was received on.
int id
Packet ID (used to link requests/responses).
uint8_t * data
Packet data (body).
size_t data_len
Length of packet data.
uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH]
RADIUS authentication vector.
fr_time_t timestamp
When we received the packet.
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
void fr_pair_list_sort(fr_pair_list_t *list, fr_cmp_t cmp)
Sort a doubly linked list of fr_pair_ts using merge sort.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
#define fr_pair_list_log(_log, _lvl, _list)
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
int af
AF_INET, AF_INET6, or AF_UNIX.
int type
SOCK_STREAM, SOCK_DGRAM, etc.
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
char const * fr_strerror(void)
Get the last library error.
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
#define RADIUSD_MAGIC_NUMBER
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out