This is a debug tool to display the RADIUS traffic on the
[freeradius.git] / src / main / radsniff.c
1 /*
2  *  radsniff.c  Display the RADIUS traffic on the network.
3  *
4  *  Version:    $Id$
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation; either version 2
9  *  of the License, or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  *
20  *  Copyright 2006  The FreeRADIUS server project
21  *  Copyright 2006  Nicolas Baradakis <nicolas.baradakis@cegetel.net>
22  */
23
24 #include <freeradius-devel/autoconf.h>
25
26 #include <pcap.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <unistd.h>
33
34 #define _LIBRADIUS 1
35 #include <freeradius-devel/radpaths.h>
36 #include <freeradius-devel/conf.h>
37 #include <freeradius-devel/libradius.h>
38 #include <freeradius-devel/radsniff.h>
39
40 static const char *radius_secret = "testing123";
41 static VALUE_PAIR *filter_vps = NULL;
42
43 static const char *packet_codes[] = {
44   "",
45   "Access-Request",
46   "Access-Accept",
47   "Access-Reject",
48   "Accounting-Request",
49   "Accounting-Response",
50   "Accounting-Status",
51   "Password-Request",
52   "Password-Accept",
53   "Password-Reject",
54   "Accounting-Message",
55   "Access-Challenge",
56   "Status-Server",
57   "Status-Client",
58   "14",
59   "15",
60   "16",
61   "17",
62   "18",
63   "19",
64   "20",
65   "Resource-Free-Request",
66   "Resource-Free-Response",
67   "Resource-Query-Request",
68   "Resource-Query-Response",
69   "Alternate-Resource-Reclaim-Request",
70   "NAS-Reboot-Request",
71   "NAS-Reboot-Response",
72   "28",
73   "Next-Passcode",
74   "New-Pin",
75   "Terminate-Session",
76   "Password-Expired",
77   "Event-Request",
78   "Event-Response",
79   "35",
80   "36",
81   "37",
82   "38",
83   "39",
84   "Disconnect-Request",
85   "Disconnect-ACK",
86   "Disconnect-NAK",
87   "CoF-Request",
88   "CoF-ACK",
89   "CoF-NAK",
90   "46",
91   "47",
92   "48",
93   "49",
94   "IP-Address-Allocate",
95   "IP-Address-Release"
96 };
97
98 /*
99  *      Stolen from rad_recv() in ../lib/radius.c
100  */
101 static RADIUS_PACKET *init_packet(const uint8_t *data, size_t data_len)
102 {
103         RADIUS_PACKET           *packet;
104         uint8_t                 *attr;
105         int                     totallen;
106         int                     count;
107         radius_packet_t         *hdr;
108         char                    host_ipaddr[128];
109         int                     seen_eap;
110         int                     num_attributes;
111
112         /*
113          *      Allocate the new request data structure
114          */
115         if ((packet = malloc(sizeof(*packet))) == NULL) {
116                 librad_log("out of memory");
117                 return NULL;
118         }
119         memset(packet, 0, sizeof(*packet));
120
121 /*      packet->data_len = rad_recvfrom(fd, &packet->data, 0, */
122 /*                                      &packet->src_ipaddr, &packet->src_port, */
123 /*                                      &packet->dst_ipaddr, &packet->dst_port); */
124
125         packet->data = data;
126         packet->data_len = data_len;
127
128         /*
129          *      Check for socket errors.
130          */
131 /*      if (packet->data_len < 0) { */
132 /*              librad_log("Error receiving packet: %s", strerror(errno)); */
133 /*              /\* packet->data is NULL *\/ */
134 /*              free(packet); */
135 /*              return NULL; */
136 /*      } */
137
138         /*
139          *      Fill IP header fields.  We need these for the error
140          *      messages which may come later.
141          */
142 /*      packet->sockfd = fd; */
143
144         /*
145          *      FIXME: Do even more filtering by only permitting
146          *      certain IP's.  The problem is that we don't know
147          *      how to do this properly for all possible clients...
148          */
149
150         /*
151          *      Explicitely set the VP list to empty.
152          */
153         packet->vps = NULL;
154
155         /*
156          *      Check for packets smaller than the packet header.
157          *
158          *      RFC 2865, Section 3., subsection 'length' says:
159          *
160          *      "The minimum length is 20 ..."
161          */
162         if (packet->data_len < AUTH_HDR_LEN) {
163                 librad_log("WARNING: Malformed RADIUS packet from host %s: too short (received %d < minimum %d)",
164                            inet_ntop(packet->src_ipaddr.af,
165                                      &packet->src_ipaddr.ipaddr,
166                                      host_ipaddr, sizeof(host_ipaddr)),
167                            packet->data_len, AUTH_HDR_LEN);
168                 rad_free(&packet);
169                 return NULL;
170         }
171
172         /*
173          *      RFC 2865, Section 3., subsection 'length' says:
174          *
175          *      " ... and maximum length is 4096."
176          */
177         if (packet->data_len > MAX_RADIUS_LEN) {
178                 librad_log("WARNING: Malformed RADIUS packet from host %s: too long (received %d > maximum %d)",
179                            inet_ntop(packet->src_ipaddr.af,
180                                      &packet->src_ipaddr.ipaddr,
181                                      host_ipaddr, sizeof(host_ipaddr)),
182                            packet->data_len, MAX_RADIUS_LEN);
183                 rad_free(&packet);
184                 return NULL;
185         }
186
187         /*
188          *      Check for packets with mismatched size.
189          *      i.e. We've received 128 bytes, and the packet header
190          *      says it's 256 bytes long.
191          */
192         totallen = (packet->data[2] << 8) | packet->data[3];
193         hdr = (radius_packet_t *)packet->data;
194
195         /*
196          *      Code of 0 is not understood.
197          *      Code of 16 or greate is not understood.
198          */
199         if ((hdr->code == 0) ||
200             (hdr->code >= 52)) {
201                 librad_log("WARNING: Bad RADIUS packet from host %s: unknown packet code %d",
202                            inet_ntop(packet->src_ipaddr.af,
203                                      &packet->src_ipaddr.ipaddr,
204                                      host_ipaddr, sizeof(host_ipaddr)),
205                            hdr->code);
206                 rad_free(&packet);
207                 return NULL;
208         }
209
210         /*
211          *      Repeat the length checks.  This time, instead of
212          *      looking at the data we received, look at the value
213          *      of the 'length' field inside of the packet.
214          *
215          *      Check for packets smaller than the packet header.
216          *
217          *      RFC 2865, Section 3., subsection 'length' says:
218          *
219          *      "The minimum length is 20 ..."
220          */
221         if (totallen < AUTH_HDR_LEN) {
222                 librad_log("WARNING: Malformed RADIUS packet from host %s: too short (length %d < minimum %d)",
223                            inet_ntop(packet->src_ipaddr.af,
224                                      &packet->src_ipaddr.ipaddr,
225                                      host_ipaddr, sizeof(host_ipaddr)),
226                            totallen, AUTH_HDR_LEN);
227                 rad_free(&packet);
228                 return NULL;
229         }
230
231         /*
232          *      And again, for the value of the 'length' field.
233          *
234          *      RFC 2865, Section 3., subsection 'length' says:
235          *
236          *      " ... and maximum length is 4096."
237          */
238         if (totallen > MAX_RADIUS_LEN) {
239                 librad_log("WARNING: Malformed RADIUS packet from host %s: too long (length %d > maximum %d)",
240                            inet_ntop(packet->src_ipaddr.af,
241                                      &packet->src_ipaddr.ipaddr,
242                                      host_ipaddr, sizeof(host_ipaddr)),
243                            totallen, MAX_RADIUS_LEN);
244                 rad_free(&packet);
245                 return NULL;
246         }
247
248         /*
249          *      RFC 2865, Section 3., subsection 'length' says:
250          *
251          *      "If the packet is shorter than the Length field
252          *      indicates, it MUST be silently discarded."
253          *
254          *      i.e. No response to the NAS.
255          */
256         if (packet->data_len < totallen) {
257                 librad_log("WARNING: Malformed RADIUS packet from host %s: received %d octets, packet length says %d",
258                            inet_ntop(packet->src_ipaddr.af,
259                                      &packet->src_ipaddr.ipaddr,
260                                      host_ipaddr, sizeof(host_ipaddr)),
261                            packet->data_len, totallen);
262                 rad_free(&packet);
263                 return NULL;
264         }
265
266         /*
267          *      RFC 2865, Section 3., subsection 'length' says:
268          *
269          *      "Octets outside the range of the Length field MUST be
270          *      treated as padding and ignored on reception."
271          */
272         if (packet->data_len > totallen) {
273                 /*
274                  *      We're shortening the packet below, but just
275                  *      to be paranoid, zero out the extra data.
276                  */
277                 memset(packet->data + totallen, 0, packet->data_len - totallen);
278                 packet->data_len = totallen;
279         }
280
281         /*
282          *      Walk through the packet's attributes, ensuring that
283          *      they add up EXACTLY to the size of the packet.
284          *
285          *      If they don't, then the attributes either under-fill
286          *      or over-fill the packet.  Any parsing of the packet
287          *      is impossible, and will result in unknown side effects.
288          *
289          *      This would ONLY happen with buggy RADIUS implementations,
290          *      or with an intentional attack.  Either way, we do NOT want
291          *      to be vulnerable to this problem.
292          */
293         attr = hdr->data;
294         count = totallen - AUTH_HDR_LEN;
295         seen_eap = 0;
296         num_attributes = 0;
297
298         while (count > 0) {
299                 /*
300                  *      Attribute number zero is NOT defined.
301                  */
302                 if (attr[0] == 0) {
303                         librad_log("WARNING: Malformed RADIUS packet from host %s: Invalid attribute 0",
304                                    inet_ntop(packet->src_ipaddr.af,
305                                              &packet->src_ipaddr.ipaddr,
306                                              host_ipaddr, sizeof(host_ipaddr)));
307                         rad_free(&packet);
308                         return NULL;
309                 }
310
311                 /*
312                  *      Attributes are at LEAST as long as the ID & length
313                  *      fields.  Anything shorter is an invalid attribute.
314                  */
315                 if (attr[1] < 2) {
316                         librad_log("WARNING: Malformed RADIUS packet from host %s: attribute %d too short",
317                                    inet_ntop(packet->src_ipaddr.af,
318                                              &packet->src_ipaddr.ipaddr,
319                                              host_ipaddr, sizeof(host_ipaddr)),
320                                    attr[0]);
321                         rad_free(&packet);
322                         return NULL;
323                 }
324
325                 /*
326                  *      Sanity check the attributes for length.
327                  */
328                 switch (attr[0]) {
329                 default:        /* don't do anything by default */
330                         break;
331
332                 case PW_EAP_MESSAGE:
333                         seen_eap |= PW_EAP_MESSAGE;
334                         break;
335
336                 case PW_MESSAGE_AUTHENTICATOR:
337                         if (attr[1] != 2 + AUTH_VECTOR_LEN) {
338                                 librad_log("WARNING: Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
339                                            inet_ntop(packet->src_ipaddr.af,
340                                                      &packet->src_ipaddr.ipaddr,
341                                                      host_ipaddr, sizeof(host_ipaddr)),
342                                            attr[1] - 2);
343                                 rad_free(&packet);
344                                 return NULL;
345                         }
346                         seen_eap |= PW_MESSAGE_AUTHENTICATOR;
347                         break;
348                 }
349
350                 /*
351                  *      FIXME: Look up the base 255 attributes in the
352                  *      dictionary, and switch over their type.  For
353                  *      integer/date/ip, the attribute length SHOULD
354                  *      be 6.
355                  */
356                 count -= attr[1];       /* grab the attribute length */
357                 attr += attr[1];
358                 num_attributes++;       /* seen one more attribute */
359         }
360
361         /*
362          *      If the attributes add up to a packet, it's allowed.
363          *
364          *      If not, we complain, and throw the packet away.
365          */
366         if (count != 0) {
367                 librad_log("WARNING: Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
368                            inet_ntop(packet->src_ipaddr.af,
369                                      &packet->src_ipaddr.ipaddr,
370                                      host_ipaddr, sizeof(host_ipaddr)));
371                 rad_free(&packet);
372                 return NULL;
373         }
374
375         /*
376          *      If we're configured to look for a maximum number of
377          *      attributes, and we've seen more than that maximum,
378          *      then throw the packet away, as a possible DoS.
379          */
380         if ((librad_max_attributes > 0) &&
381             (num_attributes > librad_max_attributes)) {
382                 librad_log("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
383                            inet_ntop(packet->src_ipaddr.af,
384                                      &packet->src_ipaddr.ipaddr,
385                                      host_ipaddr, sizeof(host_ipaddr)),
386                            num_attributes, librad_max_attributes);
387                 rad_free(&packet);
388                 return NULL;
389         }
390
391         /*
392          *      http://www.freeradius.org/rfc/rfc2869.html#EAP-Message
393          *
394          *      A packet with an EAP-Message attribute MUST also have
395          *      a Message-Authenticator attribute.
396          *
397          *      A Message-Authenticator all by itself is OK, though.
398          */
399         if (seen_eap &&
400             (seen_eap != PW_MESSAGE_AUTHENTICATOR) &&
401             (seen_eap != (PW_EAP_MESSAGE | PW_MESSAGE_AUTHENTICATOR))) {
402                 librad_log("WARNING: Insecure packet from host %s:  Received EAP-Message with no Message-Authenticator.",
403                            inet_ntop(packet->src_ipaddr.af,
404                                      &packet->src_ipaddr.ipaddr,
405                                      host_ipaddr, sizeof(host_ipaddr)));
406                 rad_free(&packet);
407                 return NULL;
408         }
409
410         if (librad_debug) {
411                 if ((hdr->code > 0) && (hdr->code < 52)) {
412                         printf("rad_recv: %s packet from host %s port %d",
413                                packet_codes[hdr->code],
414                                inet_ntop(packet->src_ipaddr.af,
415                                          &packet->src_ipaddr.ipaddr,
416                                          host_ipaddr, sizeof(host_ipaddr)),
417                                packet->src_port);
418                 } else {
419                         printf("rad_recv: Packet from host %s port %d code=%d",
420                                inet_ntop(packet->src_ipaddr.af,
421                                          &packet->src_ipaddr.ipaddr,
422                                          host_ipaddr, sizeof(host_ipaddr)),
423                                packet->src_port,
424                                hdr->code);
425                 }
426                 printf(", id=%d, length=%d\n", hdr->id, totallen);
427         }
428
429         /*
430          *      Fill RADIUS header fields
431          */
432         packet->code = hdr->code;
433         packet->id = hdr->id;
434         memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN);
435
436         return packet;
437 }
438
439 /*
440  *      Stolen from rad_decode() in ../lib/radius.c
441  */
442 static int decode_packet(RADIUS_PACKET *packet, const char *secret)
443 {
444         uint32_t                lvalue;
445         uint32_t                vendorcode;
446         VALUE_PAIR              **tail;
447         VALUE_PAIR              *pair;
448         uint8_t                 *ptr;
449         int                     packet_length;
450         int                     attribute;
451         int                     attrlen;
452         int                     vendorlen;
453         radius_packet_t         *hdr;
454         int                     vsa_tlen, vsa_llen;
455         DICT_VENDOR             *dv = NULL;
456
457 /*      if (rad_verify(packet, original, secret) < 0) return -1; */
458
459         /*
460          *      Extract attribute-value pairs
461          */
462         hdr = (radius_packet_t *)packet->data;
463         ptr = hdr->data;
464         packet_length = packet->data_len - AUTH_HDR_LEN;
465
466         /*
467          *      There may be VP's already in the packet.  Don't
468          *      destroy them.
469          */
470         for (tail = &packet->vps; *tail != NULL; tail = &((*tail)->next)) {
471                 /* nothing */
472         }
473
474         vendorcode = 0;
475         vendorlen  = 0;
476         vsa_tlen = vsa_llen = 1;
477
478         /*
479          *      We have to read at least two bytes.
480          *
481          *      rad_recv() above ensures that this is OK.
482          */
483         while (packet_length > 0) {
484                 attribute = -1;
485                 attrlen = -1;
486
487                 /*
488                  *      Normal attribute, handle it like normal.
489                  */
490                 if (vendorcode == 0) {
491                         /*
492                          *      No room to read attr/length,
493                          *      or bad attribute, or attribute is
494                          *      too short, or attribute is too long,
495                          *      stop processing the packet.
496                          */
497                         if ((packet_length < 2) ||
498                             (ptr[0] == 0) ||  (ptr[1] < 2) ||
499                             (ptr[1] > packet_length)) break;
500
501                         attribute = *ptr++;
502                         attrlen   = *ptr++;
503
504                         attrlen -= 2;
505                         packet_length  -= 2;
506
507                         if (attribute != PW_VENDOR_SPECIFIC) goto create_pair;
508
509                         /*
510                          *      No vendor code, or ONLY vendor code.
511                          */
512                         if (attrlen <= 4) goto create_pair;
513
514                         vendorlen = 0;
515                 }
516
517                 /*
518                  *      Handle Vendor-Specific
519                  */
520                 if (vendorlen == 0) {
521                         uint8_t *subptr;
522                         int sublen;
523                         int myvendor;
524
525                         /*
526                          *      attrlen was checked above.
527                          */
528                         memcpy(&lvalue, ptr, 4);
529                         myvendor = ntohl(lvalue);
530
531                         /*
532                          *      Zero isn't allowed.
533                          */
534                         if (myvendor == 0) goto create_pair;
535
536                         /*
537                          *      This is an implementation issue.
538                          *      We currently pack vendor into the upper
539                          *      16 bits of a 32-bit attribute number,
540                          *      so we can't handle vendor numbers larger
541                          *      than 16 bits.
542                          */
543                         if (myvendor > 65535) goto create_pair;
544
545                         vsa_tlen = vsa_llen = 1;
546                         dv = dict_vendorbyvalue(myvendor);
547                         if (dv) {
548                                 vsa_tlen = dv->type;
549                                 vsa_llen = dv->length;
550                         }
551
552                         /*
553                          *      Sweep through the list of VSA's,
554                          *      seeing if they exactly fill the
555                          *      outer Vendor-Specific attribute.
556                          *
557                          *      If not, create a raw Vendor-Specific.
558                          */
559                         subptr = ptr + 4;
560                         sublen = attrlen - 4;
561
562                         /*
563                          *      See if we can parse it.
564                          */
565                         do {
566                                 int myattr = 0;
567
568                                 /*
569                                  *      Don't have a type, it's bad.
570                                  */
571                                 if (sublen < vsa_tlen) goto create_pair;
572
573                                 /*
574                                  *      Ensure that the attribute number
575                                  *      is OK.
576                                  */
577                                 switch (vsa_tlen) {
578                                 case 1:
579                                         myattr = subptr[0];
580                                         break;
581
582                                 case 2:
583                                         myattr = (subptr[0] << 8) | subptr[1];
584                                         break;
585
586                                 case 4:
587                                         if ((subptr[0] != 0) ||
588                                             (subptr[1] != 0)) goto create_pair;
589
590                                         myattr = (subptr[2] << 8) | subptr[3];
591                                         break;
592
593                                         /*
594                                          *      Our dictionary is broken.
595                                          */
596                                 default:
597                                         goto create_pair;
598                                 }
599
600                                 /*
601                                  *      Not enough room for one more
602                                  *      attribute.  Die!
603                                  */
604                                 if (sublen < vsa_tlen + vsa_llen) goto create_pair;
605                                 switch (vsa_llen) {
606                                 case 0:
607                                         attribute = (myvendor << 16) | myattr;
608                                         ptr += 4 + vsa_tlen;
609                                         attrlen -= (4 + vsa_tlen);
610                                         packet_length -= 4 + vsa_tlen;
611                                         goto create_pair;
612
613                                 case 1:
614                                         if (subptr[vsa_tlen] < (vsa_tlen + vsa_llen))
615                                                 goto create_pair;
616
617                                         if (subptr[vsa_tlen] > sublen)
618                                                 goto create_pair;
619                                         sublen -= subptr[vsa_tlen];
620                                         subptr += subptr[vsa_tlen];
621                                         break;
622
623                                 case 2:
624                                         if (subptr[vsa_tlen] != 0) goto create_pair;
625                                         if (subptr[vsa_tlen + 1] < (vsa_tlen + vsa_llen))
626                                                 goto create_pair;
627                                         if (subptr[vsa_tlen + 1] > sublen)
628                                                 goto create_pair;
629                                         sublen -= subptr[vsa_tlen + 1];
630                                         subptr += subptr[vsa_tlen + 1];
631                                         break;
632
633                                         /*
634                                          *      Our dictionaries are
635                                          *      broken.
636                                          */
637                                 default:
638                                         goto create_pair;
639                                 }
640                         } while (sublen > 0);
641
642                         vendorcode = myvendor;
643                         vendorlen = attrlen - 4;
644                         packet_length -= 4;
645
646                         ptr += 4;
647                 }
648
649                 /*
650                  *      attrlen is the length of this attribute.
651                  *      total_len is the length of the encompassing
652                  *      attribute.
653                  */
654                 switch (vsa_tlen) {
655                 case 1:
656                         attribute = ptr[0];
657                         break;
658
659                 case 2:
660                         attribute = (ptr[0] << 8) | ptr[1];
661                         break;
662
663                 default:        /* can't hit this. */
664                         return -1;
665                 }
666                 attribute |= (vendorcode << 16);
667                 ptr += vsa_tlen;
668
669                 switch (vsa_llen) {
670                 case 1:
671                         attrlen = ptr[0] - (vsa_tlen + vsa_llen);
672                         break;
673
674                 case 2:
675                         attrlen = ptr[1] - (vsa_tlen + vsa_llen);
676                         break;
677
678                 default:        /* can't hit this. */
679                         return -1;
680                 }
681                 ptr += vsa_llen;
682                 vendorlen -= vsa_tlen + vsa_llen + attrlen;
683                 if (vendorlen == 0) vendorcode = 0;
684                 packet_length -= (vsa_tlen + vsa_llen);
685
686                 /*
687                  *      Create the attribute, setting the default type
688                  *      to 'octects'.  If the type in the dictionary
689                  *      is different, then the dictionary type will
690                  *      over-ride this one.
691                  */
692         create_pair:
693 /*              pair = rad_attr2vp(packet, original, secret, */
694 /*                               attribute, attrlen, ptr); */
695                 pair = rad_attr2vp(packet, NULL, secret,
696                                  attribute, attrlen, ptr);
697                 if (!pair) {
698                         pairfree(&packet->vps);
699                         librad_log("out of memory");
700                         return -1;
701                 }
702
703                 debug_pair(pair);
704                 *tail = pair;
705                 tail = &pair->next;
706
707                 ptr += attrlen;
708                 packet_length -= attrlen;
709         }
710
711         /*
712          *      Merge information from the outside world into our
713          *      random pool.
714          */
715         lrad_rand_seed(packet->data, AUTH_HDR_LEN);
716
717         return 0;
718 }
719
720 static int filter_packet(RADIUS_PACKET *packet)
721 {
722         VALUE_PAIR *check_item;
723         VALUE_PAIR *vp;
724         unsigned int pass, fail;
725         int compare;
726
727         pass = fail = 0;
728         for (vp = packet->vps; vp != NULL; vp = vp->next) {
729                 for (check_item = filter_vps;
730                      check_item != NULL;
731                      check_item = check_item->next)
732                         if ((check_item->attribute == vp->attribute)
733                          && (check_item->operator != T_OP_SET)) {
734                                 compare = paircmp(check_item, vp);
735                                 if (compare == 1)
736                                         pass++;
737                                 else
738                                         fail++;
739                         }
740         }
741         if (fail == 0 && pass != 0) {
742                 return 0;
743         }
744
745         return 1;
746 }
747
748 static void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
749 {
750         /* Just a counter of how many packets we've had */
751         static int count = 1;
752         /* Define pointers for packet's attributes */
753         const struct ethernet_header *ethernet;  /* The ethernet header */
754         const struct ip_header *ip;              /* The IP header */
755         const struct udp_header *udp;            /* The UDP header */
756         const char *payload;                     /* Packet payload */
757         /* And define the size of the structures we're using */
758         int size_ethernet = sizeof(struct ethernet_header);
759         int size_ip = sizeof(struct ip_header);
760         int size_udp = sizeof(struct udp_header);
761         /* For FreeRADIUS */
762         RADIUS_PACKET *request;
763
764         /* Define our packet's attributes */
765         ethernet = (struct ethernet_header*)(packet);
766         ip = (struct ip_header*)(packet + size_ethernet);
767         udp = (struct udp_header*)(packet + size_ethernet + size_ip);
768         payload = (u_char *)(packet + size_ethernet + size_ip + size_udp);
769
770         /* Read the RADIUS packet structure */
771         request = init_packet(payload, header->len - size_ethernet - size_ip - size_udp);
772         if (request == NULL) {
773                 librad_perror("check");
774                 return;
775         }
776         request->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
777         request->src_port = ntohs(udp->udp_sport);
778         request->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
779         request->dst_port = ntohs(udp->udp_dport);
780         if (decode_packet(request, radius_secret) != 0) {
781                 librad_perror("decode");
782                 return;
783         }
784         if (filter_vps && filter_packet(request)) {
785                 /* printf("Packet number %d doesn't match\n", count++); */
786                 return;
787         }
788
789         /* Print the RADIUS packet */
790         printf("Packet number %d has just been sniffed\n", count++);
791         printf("\tFrom:    %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
792         printf("\tTo:      %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
793         printf("\tType:    %s\n", packet_codes[request->code]);
794         if (request->vps != NULL) {
795                 vp_printlist(stdout, request->vps);
796                 pairfree(&request->vps);
797         }
798         free(request);
799 }
800
801 static void NEVER_RETURNS usage(int status)
802 {
803         FILE *output = status ? stderr : stdout;
804         fprintf(output, "usage: radsniff [options]\n");
805         fprintf(output, "options:\n");
806         fprintf(output, "\t-c count\tNumber of packets to capture.\n");
807         fprintf(output, "\t-f filter\tPCAP filter. (default is udp port 1812 or 1813 or 1814)\n");
808         fprintf(output, "\t-h\t\tPrint this help message.\n");
809         fprintf(output, "\t-i interface\tInterface to capture.\n");
810         fprintf(output, "\t-r filter\tRADIUS filter.\n");
811         fprintf(output, "\t-s secret\tRADIUS secret.\n");
812         exit(status);
813 }
814
815 int main(int argc, char *argv[])
816 {
817         char *dev;                      /* sniffing device */
818         char errbuf[PCAP_ERRBUF_SIZE];  /* error buffer */
819         pcap_t *descr;                  /* sniff handler */
820         struct bpf_program fp;          /* hold compiled program */
821         bpf_u_int32 maskp;              /* subnet mask */
822         bpf_u_int32 netp;               /* ip */
823         char *pcap_filter = "udp port 1812 or 1813 or 1814";
824         char *radius_filter = NULL;
825         int packet_count = -1;          /* how many packets to sniff */
826         int opt;
827         LRAD_TOKEN parsecode;
828
829         /* For FreeRADIUS */
830         const char radius_dir[] = RADIUS_DIR;
831         if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
832                 librad_perror("radsniff");
833                 return 1;
834         }
835
836         /* Default device */
837         dev = pcap_lookupdev(errbuf);
838
839         /* Get options */
840         while ((opt = getopt(argc, argv, "c:f:hi:r:s:")) != EOF) {
841                 switch (opt)
842                 {
843                 case 'c':
844                         packet_count = atoi(optarg);
845                         if (packet_count <= 0) {
846                                 fprintf(stderr, "radsniff: Invalid number of packets \"%s\"\n", optarg);
847                                 exit(1);
848                         }
849                         break;
850                 case 'f':
851                         pcap_filter = optarg;
852                         break;
853                 case 'h':
854                         usage(0);
855                         break;
856                 case 'i':
857                         dev = optarg;
858                         break;
859                 case 'r':
860                         radius_filter = optarg;
861                         parsecode = userparse(radius_filter, &filter_vps);
862                         if (parsecode == T_OP_INVALID || filter_vps == NULL) {
863                                 fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\"\n", optarg);
864                                 exit(1);
865                         }
866                         break;
867                 case 's':
868                         radius_secret = optarg;
869                         break;
870                 default:
871                         usage(1);
872                 }
873         }
874
875         /* Set our device */
876         pcap_lookupnet(dev, &netp, &maskp, errbuf);
877
878         /* Print device to the user */
879         printf("Device: [%s]\n", dev);
880         if (packet_count > 0) {
881                 printf("Num of packets: [%d]\n", packet_count);
882         }
883         printf("PCAP filter: [%s]\n", pcap_filter);
884         if (filter_vps != NULL) {
885                 printf("RADIUS filter:\n");
886                 vp_printlist(stdout, filter_vps);
887         }
888         printf("RADIUS secret: [%s]\n", radius_secret);
889
890         /* Open the device so we can spy */
891         descr = pcap_open_live(dev, SNAPLEN, 1, 0, errbuf);
892         if (descr == NULL)
893         {
894                 printf("radsniff: pcap_open_live failed (%s)\n", errbuf);
895                 exit(1);
896         }
897
898         /* Apply the rules */
899         if( pcap_compile(descr, &fp, pcap_filter, 0, netp) == -1)
900         {
901                 printf("radsniff: pcap_compile failed\n");
902                 exit(1);
903         }
904         if (pcap_setfilter(descr, &fp) == -1)
905         {
906                 printf("radsniff: pcap_setfilter failed\n");
907                 exit(1);
908         }
909
910         /* Now we can set our callback function */
911         pcap_loop(descr, packet_count, got_packet, NULL);
912         pcap_close(descr);
913
914         printf("Done sniffing\n");
915         return 0;
916 }