static const char *radius_secret = "testing123";
static VALUE_PAIR *filter_vps = NULL;
-#undef DEBUG
-#define DEBUG if (fr_debug_flag) printf
-static int minimal = 0;
static int do_sort = 0;
+static int to_stdout = 0;
+static FILE *log_dst;
+
+#undef DEBUG1
+#define DEBUG1 if (fr_debug_flag > 2) fprintf
+#undef DEBUG
+#define DEBUG if (fr_debug_flag > 1) fprintf
+#undef INFO
+#define INFO if (fr_debug_flag > 0) fprintf
+
struct timeval start_pcap = {0, 0};
static rbtree_t *filter_tree = NULL;
static rbtree_t *request_tree = NULL;
-static pcap_dumper_t *pcap_dumper = NULL;
+static pcap_dumper_t *out = NULL;
static RADIUS_PACKET *nullpacket = NULL;
typedef int (*rbcmp)(const void *, const void *);
+static const char *radsniff_version = "radsniff version " RADIUSD_VERSION_STRING
+#ifdef RADIUSD_VERSION_COMMIT
+" (git #" RADIUSD_VERSION_COMMIT ")"
+#endif
+;
+
static int filter_packet(RADIUS_PACKET *packet)
{
VALUE_PAIR *check_item;
}
}
-
if (fail == 0 && pass != 0) {
/*
* Cache authentication requests, as the replies
}
}
-static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const uint8_t *data)
+static void got_packet(UNUSED uint8_t *args, const struct pcap_pkthdr *header, const uint8_t *data)
{
- /* Just a counter of how many packets we've had */
- static int count = 1;
- /* Define pointers for packet's attributes */
- const struct ethernet_header *ethernet; /* The ethernet header */
- const struct ip_header *ip; /* The IP header */
- const struct udp_header *udp; /* The UDP header */
- const uint8_t *payload; /* Packet payload */
- /* And define the size of the structures we're using */
+
+ static int count = 1; /* Packets seen */
+
+ /*
+ * Define pointers for packet's attributes
+ */
+ const struct ethernet_header *ethernet; /* The ethernet header */
+ const struct ip_header *ip; /* The IP header */
+ const struct udp_header *udp; /* The UDP header */
+ const uint8_t *payload; /* Packet payload */
+
+ /*
+ * And define the size of the structures we're using
+ */
int size_ethernet = sizeof(struct ethernet_header);
int size_ip = sizeof(struct ip_header);
int size_udp = sizeof(struct udp_header);
- /* For FreeRADIUS */
+
+ /*
+ * For FreeRADIUS
+ */
RADIUS_PACKET *packet, *original;
struct timeval elapsed;
- args = args; /* -Wunused */
-
- /* Define our packet's attributes */
+ /*
+ * Define our packet's attributes
+ */
if ((data[0] == 2) && (data[1] == 0) &&
(data[2] == 0) && (data[3] == 0)) {
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->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
packet->dst_port = ntohs(udp->udp_dport);
- packet->data = payload;
+ memcpy(&packet->data, &payload, sizeof(packet->data));
packet->data_len = header->len - (payload - data);
if (!rad_packet_ok(packet, 0)) {
- printf("Packet: %s\n", fr_strerror());
+ DEBUG(log_dst, "Packet: %s\n", fr_strerror());
- 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]);
+ DEBUG(log_dst, " From %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
+ DEBUG(log_dst, " To: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
+ DEBUG(log_dst, " Type: %s\n", fr_packet_codes[packet->code]);
free(packet);
return;
}
/*
- * Decode the data without bothering to check the signatures.
+ * Decode the data without bothering to check the signatures.
*/
if (rad_decode(packet, original, radius_secret) != 0) {
free(packet);
return;
}
- /* we've seen a successfull reply to this, so delete it now */
+ /*
+ * We've seen a successfull reply to this, so delete it now
+ */
if (original)
rbtree_deletebydata(request_tree, original);
if (filter_vps && filter_packet(packet)) {
free(packet);
- DEBUG("Packet number %d doesn't match\n", count++);
+ DEBUG(log_dst, "Packet number %d doesn't match\n", count++);
return;
}
- if (pcap_dumper) {
- pcap_dump((void *) pcap_dumper, header, data);
+ if (out) {
+ pcap_dump((void *) out, 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++);
+ INFO(log_dst, "%s Id %d\t", fr_packet_codes[packet->code], packet->id);
+ /*
+ * Print the RADIUS packet
+ */
+ INFO(log_dst, "%s:%d -> ", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
+ INFO(log_dst, "%s:%d", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
+
+ DEBUG1(log_dst, "\t(%d packets)", count++);
+
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,
+ INFO(log_dst, "\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);
+
+ if (fr_debug_flag > 1) {
+ DEBUG(log_dst, "\n");
+ if (packet->vps) {
+ if (do_sort) sort(packet);
+
+ vp_printlist(log_dst, packet->vps);
+ pairfree(&packet->vps);
+ }
+ }
+
+ INFO(log_dst, "\n");
+
+ if (!to_stdout && (fr_debug_flag > 4)) {
+ rad_print_hex(packet);
}
- printf("\n");
- if (fr_debug_flag > 2) rad_print_hex(packet);
- fflush(stdout);
+
+ fflush(log_dst);
check_filter:
/*
- * If we're doing filtering, Access-Requests are cached
- * in the filter tree.
+ * If we're doing filtering, Access-Requests are cached in the
+ * filter tree.
*/
if (!filter_vps ||
((packet->code != PW_AUTHENTICATION_REQUEST) &&
static void NEVER_RETURNS usage(int status)
{
FILE *output = status ? stderr : stdout;
- fprintf(output, "usage: radsniff [options]\n");
+ fprintf(output, "Usage: radsniff [options]\n");
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\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\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-w file\tWrite output packets to file.\n");
- fprintf(output, "\t-x\t\tPrint out debugging information.\n");
+ fprintf(output, " -c <count> Number of packets to capture.\n");
+ fprintf(output, " -d <directory> Set dictionary directory.\n");
+ fprintf(output, " -F Filter PCAP file from stdin to stdout.\n");
+ fprintf(output, " -f <filter> PCAP filter (default is 'udp port <port> or <port + 1> or 3799')\n");
+ fprintf(output, " -h This help message.\n");
+ fprintf(output, " -i <interface> Capture packets from interface (defaults to any if supported).\n");
+ fprintf(output, " -I <file> Read packets from file (overrides input of -F).\n");
+ fprintf(output, " -p <port> Filter packets by port (default is 1812).\n");
+ fprintf(output, " -q Print less debugging information.\n");
+ fprintf(output, " -r <filter> RADIUS attribute filter.\n");
+ fprintf(output, " -s <secret> RADIUS secret.\n");
+ fprintf(output, " -S Sort attributes in the packet (useful for diffing responses).\n");
+ fprintf(output, " -v Show program version information.\n");
+ fprintf(output, " -w <file> Write output packets to file (overrides output of -F).\n");
+ fprintf(output, " -x Print more debugging information (defaults to -xx).\n");
exit(status);
}
int main(int argc, char *argv[])
{
- char *dev; /* sniffing device */
- char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
- pcap_t *descr; /* sniff handler */
- struct bpf_program fp; /* hold compiled program */
- bpf_u_int32 maskp; /* subnet mask */
- bpf_u_int32 netp; /* ip */
- char buffer[1024];
- char *pcap_filter = NULL;
+ const char *from_dev = NULL; /* Capture from device */
+ const char *from_file = NULL; /* Read from pcap file */
+ int from_stdin = 0; /* Read from stdin */
+
+ pcap_t *in; /* PCAP input handle */
+
+ int limit = -1; /* How many packets to sniff */
+
+ char errbuf[PCAP_ERRBUF_SIZE]; /* Error buffer */
+
+ char *to_file = NULL; /* PCAP output file */
+
+ char *pcap_filter = NULL; /* PCAP filter string */
char *radius_filter = NULL;
- char *filename = NULL;
- int printable_output = 1;
- char *dump_file = NULL;
- int packet_count = -1; /* how many packets to sniff */
+ int port = 1812;
+
+ struct bpf_program fp; /* Holds compiled filter */
+ bpf_u_int32 ip_mask = PCAP_NETMASK_UNKNOWN; /* Device Subnet mask */
+ bpf_u_int32 ip_addr = 0; /* Device IP */
+
+ char buffer[1024];
+
int opt;
FR_TOKEN parsecode;
const char *radius_dir = RADIUS_DIR;
- int port = 1812;
- int filter_stdin = 0;
-
- /* Default device */
- dev = pcap_lookupdev(errbuf);
+
+ fr_debug_flag = 2;
+ log_dst = stdout;
- /* Get options */
- while ((opt = getopt(argc, argv, "c:d:Ff:hi:I:mp:r:s:Sw:xX")) != EOF) {
+ /*
+ * Get options
+ */
+ while ((opt = getopt(argc, argv, "c:d:Ff:hi:I:p:qr:s:Svw:xX")) != EOF) {
switch (opt)
{
case 'c':
- packet_count = atoi(optarg);
- if (packet_count <= 0) {
+ limit = atoi(optarg);
+ if (limit <= 0) {
fprintf(stderr, "radsniff: Invalid number of packets \"%s\"\n", optarg);
exit(1);
}
radius_dir = optarg;
break;
case 'F':
- filter_stdin = 1;
- printable_output = 0;
+ from_stdin = 1;
+ to_stdout = 1;
break;
case 'f':
pcap_filter = optarg;
usage(0);
break;
case 'i':
- dev = optarg;
+ from_dev = optarg;
break;
case 'I':
- filename = optarg;
- break;
- case 'm':
- minimal = 1;
+ from_file = optarg;
break;
case 'p':
port = atoi(optarg);
break;
+ case 'q':
+ if (fr_debug_flag > 0) {
+ fr_debug_flag--;
+ }
+ break;
case 'r':
radius_filter = optarg;
break;
case 'S':
do_sort = 1;
break;
+ case 'v':
+ INFO(log_dst, "%s %s\n", radsniff_version, pcap_lib_version());
+ exit(0);
+ break;
case 'w':
- dump_file = optarg;
- printable_output = 0;
+ to_file = optarg;
break;
case 'x':
- case 'X': /* for backwards compatibility */
+ case 'X':
fr_debug_flag++;
break;
default:
- usage(1);
+ usage(64);
}
}
-
+
+ /* What's the point in specifying -F ?! */
+ if (from_stdin && from_file && to_file) {
+ usage(64);
+ }
+
+ /* Can't read from both... */
+ if (from_file && from_dev) {
+ usage(64);
+ }
+
+ /* Reading from file overrides stdin */
+ if (from_stdin && (from_file || from_dev)) {
+ from_stdin = 0;
+ }
+
+ /* Writing to file overrides stdout */
+ if (to_file && to_stdout) {
+ to_stdout = 0;
+ }
+
/*
- * Cross-check command-line arguments.
+ * If were writing pcap data stdout we *really* don't want to send
+ * logging there as well.
*/
- if (filter_stdin && (filename || dump_file)) usage(1);
+ log_dst = to_stdout ? stderr : stdout;
-#ifndef HAVE_PCAP_FOPEN_OFFLINE
- if (filter_stdin) {
- fr_perror("-F is unsupported on this platform.");
- return 1;
+#if !defined(HAVE_PCAP_FOPEN_OFFLINE) || !defined(HAVE_PCAP_DUMP_FOPEN)
+ if (from_stdin || to_stdout) {
+ fprintf(stderr, "radsniff: PCAP streams not supported.\n");
+ exit(64);
}
#endif
if (!pcap_filter) {
pcap_filter = buffer;
- snprintf(buffer, sizeof(buffer), "udp port %d or %d",
- port, port + 1);
+ snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d",
+ port, port + 1, 3799);
}
/*
- * There are times when we don't need the dictionaries.
+ * There are times when we don't need the dictionaries.
*/
- if (printable_output) {
+ if (!to_stdout) {
if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
fr_perror("radsniff");
- return 1;
+ exit(64);
}
}
if (radius_filter) {
parsecode = userparse(radius_filter, &filter_vps);
if (parsecode == T_OP_INVALID) {
- fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\": %s\n", radius_filter, fr_strerror());
- exit(1);
+ fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\" (%s)\n", radius_filter, fr_strerror());
+ exit(64);
}
+
if (!filter_vps) {
fprintf(stderr, "radsniff: Empty RADIUS filter \"%s\"\n", radius_filter);
- exit(1);
+ exit(64);
}
- filter_tree = rbtree_create((rbcmp) fr_packet_cmp,
- free, 0);
+ filter_tree = rbtree_create((rbcmp) fr_packet_cmp, free, 0);
if (!filter_tree) {
fprintf(stderr, "radsniff: Failed creating filter tree\n");
exit(1);
}
}
- /* setup the request tree */
+ /*
+ * Setup the request tree
+ */
request_tree = rbtree_create((rbcmp) fr_packet_cmp, free, 0);
if (!request_tree) {
fprintf(stderr, "radsniff: Failed creating request tree\n");
exit(1);
}
- /* allocate a null packet for decrypting attributes in CoA requests */
+ /*
+ * Allocate a null packet for decrypting attributes in CoA requests
+ */
nullpacket = rad_alloc(0);
if (!nullpacket) {
fprintf(stderr, "radsniff: Out of memory\n");
exit(1);
}
- /* Set our device */
- pcap_lookupnet(dev, &netp, &maskp, errbuf);
-
- /* Print device to the user */
- if (fr_debug_flag) {
- if (dev) printf("Device: [%s]\n", dev);
- if (packet_count > 0) {
- printf("Num of packets: [%d]\n",
- packet_count);
+ /*
+ * Get the default capture device
+ */
+ if (!from_stdin && !from_file && !from_dev) {
+ from_dev = pcap_lookupdev(errbuf);
+ if (!from_dev) {
+ fprintf(stderr, "radsniff: Failed discovering default interface (%s)\n", errbuf);
+ exit(1);
}
- printf("PCAP filter: [%s]\n", pcap_filter);
- if (filter_vps) {
- printf("RADIUS filter:\n");
- vp_printlist(stdout, filter_vps);
+
+ INFO(log_dst, "Capturing from interface \"%s\"\n", from_dev);
+ }
+
+ /*
+ * Print captures values which will be used
+ */
+ if (fr_debug_flag > 2) {
+ DEBUG1(log_dst, "Sniffing with options:\n");
+ if (from_dev) DEBUG1(log_dst, " Device : [%s]\n", from_dev);
+ if (limit > 0) DEBUG1(log_dst, " Capture limit (packets) : [%d]\n", limit);
+ DEBUG1(log_dst, " PCAP filter : [%s]\n", pcap_filter);
+ DEBUG1(log_dst, " RADIUS secret : [%s]\n", radius_secret);
+ if (filter_vps){DEBUG1(log_dst, " RADIUS filter :\n");
+ vp_printlist(log_dst, filter_vps);
}
- printf("RADIUS secret: [%s]\n", radius_secret);
}
- /* Open the device so we can spy */
- if (filename) {
- descr = pcap_open_offline(filename, errbuf);
-
+ /*
+ * Figure out whether were doing a reading from a file, doing a live
+ * capture or reading from stdin.
+ */
+ if (from_file) {
+ in = pcap_open_offline(from_file, errbuf);
#ifdef HAVE_PCAP_FOPEN_OFFLINE
- } else if (filter_stdin) {
- descr = pcap_fopen_offline(stdin, errbuf);
+ } else if (from_stdin) {
+ in = pcap_fopen_offline(stdin, errbuf);
#endif
-
- } else if (!dev) {
- fprintf(stderr, "radsniff: No filename or device was specified.\n");
- exit(1);
-
+ } else if (from_dev) {
+ pcap_lookupnet(from_dev, &ip_addr, &ip_mask, errbuf);
+ in = pcap_open_live(from_dev, 65536, 1, 1, errbuf);
} else {
- descr = pcap_open_live(dev, 65536, 1, 1, errbuf);
+ fprintf(stderr, "radsniff: No capture devices available\n");
}
- if (descr == NULL)
- {
- fprintf(stderr, "radsniff: pcap_open_live failed (%s)\n", errbuf);
+
+ if (!in) {
+ fprintf(stderr, "radsniff: Failed opening input (%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));
+ if (to_file) {
+ out = pcap_dump_open(in, to_file);
+ if (!out) {
+ fprintf(stderr, "radsniff: Failed opening output file (%s)\n", pcap_geterr(in));
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));
+ } else if (to_stdout) {
+ out = pcap_dump_fopen(in, stdout);
+ if (!out) {
+ fprintf(stderr, "radsniff: Failed opening stdout (%s)\n", pcap_geterr(in));
exit(1);
}
-
#endif
}
- /* Apply the rules */
- if( pcap_compile(descr, &fp, pcap_filter, 0, netp) == -1)
- {
- fprintf(stderr, "radsniff: pcap_compile failed\n");
+ /*
+ * Apply the rules
+ */
+ if (pcap_compile(in, &fp, pcap_filter, 0, ip_mask) < 0) {
+ fprintf(stderr, "radsniff: Failed compiling PCAP filter (%s)\n", pcap_geterr(in));
exit(1);
}
- if (pcap_setfilter(descr, &fp) == -1)
- {
- fprintf(stderr, "radsniff: pcap_setfilter failed\n");
+
+ if (pcap_setfilter(in, &fp) < 0) {
+ fprintf(stderr, "radsniff: Failed applying PCAP filter (%s)\n", pcap_geterr(in));
exit(1);
}
- /* Now we can set our callback function */
- pcap_loop(descr, packet_count, got_packet, NULL);
- pcap_close(descr);
-
- if (filter_tree) rbtree_free(filter_tree);
-
- DEBUG("Done sniffing\n");
+ /*
+ * Enter the main capture loop...
+ */
+ pcap_loop(in, limit, got_packet, NULL);
+
+ /*
+ * ...were done capturing.
+ */
+ pcap_close(in);
+ if (out) {
+ pcap_dump_close(out);
+ }
+
+ if (filter_tree) {
+ rbtree_free(filter_tree);
+ }
+
+ INFO(log_dst, "Done sniffing\n");
+
return 0;
}