Added ability to write to pcap file
authorAlan T. DeKok <aland@freeradius.org>
Sat, 7 Aug 2010 21:04:19 +0000 (23:04 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 9 Aug 2010 12:06:27 +0000 (14:06 +0200)
src/main/radsniff.c

index b7bb8fa..d5c4256 100644 (file)
@@ -42,6 +42,8 @@ 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)
@@ -200,10 +202,17 @@ static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const ui
        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) {
@@ -220,14 +229,14 @@ static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const ui
        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;
@@ -247,6 +256,12 @@ static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const ui
                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 */
@@ -272,6 +287,7 @@ static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const ui
        printf("\n");
        fflush(stdout);
 
+ check_filter:
        /*
         *      If we're doing filtering, Access-Requests are cached
         *      in the filter tree.
@@ -315,6 +331,7 @@ int main(int argc, char *argv[])
        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;
@@ -325,7 +342,7 @@ int main(int argc, char *argv[])
        dev = pcap_lookupdev(errbuf);
 
        /* Get options */
-       while ((opt = getopt(argc, argv, "c:d:f:hi:I:mp:r:s:SxX")) != EOF) {
+       while ((opt = getopt(argc, argv, "c:d:f:hi:I:mp:r:s:Sw:xX")) != EOF) {
                switch (opt)
                {
                case 'c':
@@ -365,6 +382,9 @@ int main(int argc, char *argv[])
                case 'S':
                        do_sort = 1;
                        break;
+               case 'w':
+                       dump_file = optarg;
+                       break;
                case 'x':
                case 'X':       /* for backwards compatibility */
                        fr_debug_flag++;
@@ -425,12 +445,13 @@ int main(int argc, char *argv[])
        /* Open the device so we can spy */
        if (filename) {
                descr = pcap_open_offline(filename, errbuf);
+
        } 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)
        {
@@ -438,6 +459,14 @@ int main(int argc, char *argv[])
                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);
+               }
+       }
+
        /* Apply the rules */
        if( pcap_compile(descr, &fp, pcap_filter, 0, netp) == -1)
        {
@@ -446,7 +475,7 @@ int main(int argc, char *argv[])
        }
        if (pcap_setfilter(descr, &fp) == -1)
        {
-               printf("radsniff: pcap_setfilter failed\n");
+               fprintf(stderr, "radsniff: pcap_setfilter failed\n");
                exit(1);
        }