#define DEBUG if (fr_debug_flag) printf
static int minimal = 0;
+static int do_sort = 0;
+struct timeval start_pcap = {0, 0};
static rbtree_t *filter_tree = NULL;
+static pcap_dumper_t *pcap_dumper = NULL;
+
typedef int (*rbcmp)(const void *, const void *);
static int filter_packet(RADIUS_PACKET *packet)
return 1;
}
+/*
+ * Bubble goodness
+ */
+static void sort(RADIUS_PACKET *packet)
+{
+ int i, j, size;
+ VALUE_PAIR *vp, *tmp;
+ VALUE_PAIR *array[1024]; /* way more than necessary */
+
+ size = 0;
+ for (vp = packet->vps; vp != NULL; vp = vp->next) {
+ array[size++] = vp;
+ }
+
+ if (size == 0) return;
+
+ for (i = 0; i < size - 1; i++) {
+ for (j = 0; j < size - 1 - i; j++) {
+ if (array[j + 1]->attribute < array[j]->attribute) {
+ tmp = array[j];
+ array[j] = array[j + 1];
+ array[j + 1] = tmp;
+ }
+ }
+ }
+
+ /*
+ * And put them back again.
+ */
+ vp = packet->vps = array[0];
+ for (i = 1; i < size; i++) {
+ vp->next = array[i];
+ vp = array[i];
+ }
+ vp->next = NULL;
+}
+
+#define USEC 1000000
+static void tv_sub(const struct timeval *end, const struct timeval *start,
+ struct timeval *elapsed)
+{
+ elapsed->tv_sec = end->tv_sec - start->tv_sec;
+ if (elapsed->tv_sec > 0) {
+ elapsed->tv_sec--;
+ elapsed->tv_usec = USEC;
+ } else {
+ elapsed->tv_usec = 0;
+ }
+ elapsed->tv_usec += end->tv_usec;
+ elapsed->tv_usec -= start->tv_usec;
+
+ if (elapsed->tv_usec >= USEC) {
+ elapsed->tv_usec -= USEC;
+ elapsed->tv_sec++;
+ }
+}
+
static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const uint8_t *data)
{
/* Just a counter of how many packets we've had */
int size_udp = sizeof(struct udp_header);
/* For FreeRADIUS */
RADIUS_PACKET *packet;
+ struct timeval elapsed;
args = args; /* -Wunused */
/* Define our packet's attributes */
- ethernet = (const struct ethernet_header*)(data);
- ip = (const struct ip_header*)(data + size_ethernet);
- udp = (const struct udp_header*)(data + size_ethernet + size_ip);
- payload = (const uint8_t *)(data + size_ethernet + size_ip + size_udp);
+
+ if ((data[0] == 2) && (data[1] == 0) &&
+ (data[2] == 0) && (data[3] == 0)) {
+ ip = (const struct ip_header*) (data + 4);
+
+ } else {
+ ethernet = (const struct ethernet_header*)(data);
+ ip = (const struct ip_header*)(data + size_ethernet);
+ }
+ udp = (const struct udp_header*)(((const uint8_t *) ip) + size_ip);
+ payload = (const uint8_t *)(((const uint8_t *) udp) + size_udp);
packet = malloc(sizeof(*packet));
if (!packet) {
packet->dst_port = ntohs(udp->udp_dport);
packet->data = payload;
- packet->data_len = header->len - size_ethernet - size_ip - size_udp;
+ packet->data_len = header->len - (payload - data);
if (!rad_packet_ok(packet, 0)) {
- fr_perror("Packet");
+ printf("Packet: %s\n", fr_strerror());
- fprintf(stderr, "\tFrom: %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
- fprintf(stderr, "\tTo: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
- fprintf(stderr, "\tType: %s\n", fr_packet_codes[packet->code]);
+ printf("\tFrom: %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
+ printf("\tTo: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
+ printf("\tType: %s\n", fr_packet_codes[packet->code]);
free(packet);
return;
DEBUG("Packet number %d doesn't match\n", count++);
return;
}
+
+ if (pcap_dumper) {
+ pcap_dump((void *) pcap_dumper, header, data);
+ goto check_filter;
+ }
+
printf("%s Id %d\t", fr_packet_codes[packet->code], packet->id);
/* Print the RADIUS packet */
printf("%s:%d -> ", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
printf("%s:%d", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
if (fr_debug_flag) printf("\t(%d packets)", count++);
- printf("\t%08x", header->ts.tv_sec);
- printf("\n");
+
+ if (!start_pcap.tv_sec) {
+ start_pcap = header->ts;
+ }
+
+ tv_sub(&header->ts, &start_pcap, &elapsed);
+
+ printf("\t+%u.%03u", (unsigned int) elapsed.tv_sec,
+ (unsigned int) elapsed.tv_usec / 1000);
+ if (!minimal) printf("\n");
if (!minimal && packet->vps) {
+ if (do_sort) sort(packet);
+
vp_printlist(stdout, packet->vps);
pairfree(&packet->vps);
}
printf("\n");
fflush(stdout);
+ check_filter:
/*
* If we're doing filtering, Access-Requests are cached
* in the filter tree.
fprintf(output, "options:\n");
fprintf(output, "\t-c count\tNumber of packets to capture.\n");
fprintf(output, "\t-d directory\tDirectory where the dictionaries are found\n");
- fprintf(output, "\t-f filter\tPCAP filter. (default is udp port 1812 or 1813 or 1814)\n");
+ fprintf(output, "\t-F\t\tFilter PCAP file from stdin to stdout.\n");
+ fprintf(output, "\t\t\tOutput file will contain RADIUS packets.\n");
+ fprintf(output, "\t-f filter\tPCAP filter. (default is udp port 1812 or 1813)\n");
fprintf(output, "\t-h\t\tPrint this help message.\n");
fprintf(output, "\t-i interface\tInterface to capture.\n");
fprintf(output, "\t-I filename\tRead packets from filename.\n");
fprintf(output, "\t-m\t\tPrint packet headers only, not contents.\n");
- fprintf(output, "\t-p port\tList for packets on port.\n");
+ fprintf(output, "\t-p port\t\tListen for packets on port.\n");
fprintf(output, "\t-r filter\tRADIUS attribute filter.\n");
fprintf(output, "\t-s secret\tRADIUS secret.\n");
+ fprintf(output, "\t-S\t\tSort attributes in the packet.\n");
+ fprintf(output, "\t\t\tUsed to compare server results.\n");
fprintf(output, "\t-x\t\tPrint out debugging information.\n");
exit(status);
}
char *pcap_filter = NULL;
char *radius_filter = NULL;
char *filename = NULL;
+ char *dump_file = NULL;
int packet_count = -1; /* how many packets to sniff */
int opt;
FR_TOKEN parsecode;
const char *radius_dir = RADIUS_DIR;
int port = 1812;
+ int filter_stdin = 0;
/* Default device */
dev = pcap_lookupdev(errbuf);
/* Get options */
- while ((opt = getopt(argc, argv, "c:d:f:hi:I:mp:r:s:xX")) != EOF) {
+ while ((opt = getopt(argc, argv, "c:d:Ff:hi:I:mp:r:s:Sw:xX")) != EOF) {
switch (opt)
{
case 'c':
case 'd':
radius_dir = optarg;
break;
+ case 'F':
+ filter_stdin = 1;
+ break;
case 'f':
pcap_filter = optarg;
break;
case 's':
radius_secret = optarg;
break;
+ case 'S':
+ do_sort = 1;
+ break;
+ case 'w':
+ dump_file = optarg;
+ break;
case 'x':
case 'X': /* for backwards compatibility */
fr_debug_flag++;
}
}
+ /*
+ * Cross-check command-line arguments.
+ */
+ if (filter_stdin && (filename || dump_file)) usage(1);
+
+#ifndef HAVE_PCAP_FOPEN_OFFLINE
+ if (filter_stdin) {
+ fr_perror("-F is unsupported on this platform.");
+ return 1;
+ }
+#endif
+
if (!pcap_filter) {
pcap_filter = buffer;
- snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d",
- port, port + 1, port + 2);
+ snprintf(buffer, sizeof(buffer), "udp port %d or %d",
+ port, port + 1);
+ }
+
+ /*
+ * There are many times where we don't need the dictionaries.
+ */
+ if (fr_debug_flag || radius_filter) {
+ if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radsniff");
+ return 1;
+ }
}
-
- if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
- fr_perror("radsniff");
- return 1;
- }
if (radius_filter) {
parsecode = userparse(radius_filter, &filter_vps);
/* Open the device so we can spy */
if (filename) {
descr = pcap_open_offline(filename, errbuf);
+
+#ifdef HAVE_PCAP_FOPEN_OFFLINE
+ } else if (filter_stdin) {
+ descr = pcap_fopen_offline(stdin, errbuf);
+#endif
+
+ } else if (!dev) {
+ fprintf(stderr, "radsniff: No filename or device was specified.\n");
+ exit(1);
+
} else {
- descr = pcap_open_live(dev, SNAPLEN, 1, 0, errbuf);
+ descr = pcap_open_live(dev, 65536, 1, 0, errbuf);
}
if (descr == NULL)
{
- printf("radsniff: pcap_open_live failed (%s)\n", errbuf);
+ fprintf(stderr, "radsniff: pcap_open_live failed (%s)\n", errbuf);
exit(1);
}
+ if (dump_file) {
+ pcap_dumper = pcap_dump_open(descr, dump_file);
+ if (!pcap_dumper) {
+ fprintf(stderr, "radsniff: Failed opening output file (%s)\n", pcap_geterr(descr));
+ exit(1);
+ }
+
+#ifdef HAVE_PCAP_DUMP_FOPEN
+ } else if (filter_stdin) {
+ pcap_dumper = pcap_dump_fopen(descr, stdout);
+ if (!pcap_dumper) {
+ fprintf(stderr, "radsniff: Failed opening stdout: %s\n", pcap_geterr(descr));
+ exit(1);
+ }
+
+#endif
+ }
+
/* Apply the rules */
if( pcap_compile(descr, &fp, pcap_filter, 0, netp) == -1)
{
- printf("radsniff: pcap_compile failed\n");
+ fprintf(stderr, "radsniff: pcap_compile failed\n");
exit(1);
}
if (pcap_setfilter(descr, &fp) == -1)
{
- printf("radsniff: pcap_setfilter failed\n");
+ fprintf(stderr, "radsniff: pcap_setfilter failed\n");
exit(1);
}