~ubuntu-branches/ubuntu/natty/freeradius/natty-updates

« back to all changes in this revision

Viewing changes to src/main/radsniff.c

  • Committer: Bazaar Package Importer
  • Author(s): Josip Rodin
  • Date: 2009-11-23 03:57:37 UTC
  • mfrom: (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20091123035737-zsgtzhfych8hir68
Tags: 2.1.7+dfsg-1
* Adopting the package, closes: #536623.
* New upstream version, closes: #513484.
  + Fixes the blooper in unlang evaluation logic, closes: #526175.
* Used quilt (and added README.source), and moved upstream file patching
  into debian/patches/. The source is no longer in collab-maint git
  (to make it simpler for me to finally get this out the door), but
  kept the .gitignore should we need that again.
* Dropped the dialup_admin/bin/backup_radacct patch (integrated upstream).
* Dropped the raddb/Makefile patch (problem no longer exists upstream).
* Dropped the lib/packet.c lib/radius.c main/listen.c patches (was from
  upstream 2.0.5 anyway).
* Dropped references to otp.conf, it no longer exists upstream.
  Keep removing the conffile statoverride in prerm.
* Dropped references to snmp.conf, it no longer exists upstream.
  Keep removing the conffile statoverride in prerm.
* Ship /etc/freeradius/modules/* in the freeradius package.
* Stop shipping sites-enabled symlinks in the package and instead create
  them only on initial install, thanks to Matej Vela, closes: #533396.
* Add export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" to the init script
  at the request of John Morrissey, closes: #550143.
* Stop installing /var/run/freeradius in the package to silence Lintian.
  The init script already recreates it at will.
* Remove executable bit from example.pl to silence Lintian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *  radsniff.c  Display the RADIUS traffic on the network.
3
3
 *
4
 
 *  Version:    $Id: radsniff.c,v 1.13 2008/01/01 17:29:12 aland Exp $
 
4
 *  Version:    $Id$
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or
7
7
 *  modify it under the terms of the GNU General Public License
22
22
 */
23
23
 
24
24
#include <freeradius-devel/ident.h>
25
 
RCSID("$Id: radsniff.c,v 1.13 2008/01/01 17:29:12 aland Exp $")
 
25
RCSID("$Id$")
26
26
 
27
27
#define _LIBRADIUS 1
28
28
#include <freeradius-devel/libradius.h>
35
35
 
36
36
static const char *radius_secret = "testing123";
37
37
static VALUE_PAIR *filter_vps = NULL;
38
 
static int debug_flag = 0;
39
38
#undef DEBUG
40
 
#define DEBUG if (debug_flag) printf
 
39
#define DEBUG if (fr_debug_flag) printf
41
40
 
42
 
static const char *packet_codes[] = {
43
 
  "",
44
 
  "Access-Request",
45
 
  "Access-Accept",
46
 
  "Access-Reject",
47
 
  "Accounting-Request",
48
 
  "Accounting-Response",
49
 
  "Accounting-Status",
50
 
  "Password-Request",
51
 
  "Password-Accept",
52
 
  "Password-Reject",
53
 
  "Accounting-Message",
54
 
  "Access-Challenge",
55
 
  "Status-Server",
56
 
  "Status-Client",
57
 
  "14",
58
 
  "15",
59
 
  "16",
60
 
  "17",
61
 
  "18",
62
 
  "19",
63
 
  "20",
64
 
  "Resource-Free-Request",
65
 
  "Resource-Free-Response",
66
 
  "Resource-Query-Request",
67
 
  "Resource-Query-Response",
68
 
  "Alternate-Resource-Reclaim-Request",
69
 
  "NAS-Reboot-Request",
70
 
  "NAS-Reboot-Response",
71
 
  "28",
72
 
  "Next-Passcode",
73
 
  "New-Pin",
74
 
  "Terminate-Session",
75
 
  "Password-Expired",
76
 
  "Event-Request",
77
 
  "Event-Response",
78
 
  "35",
79
 
  "36",
80
 
  "37",
81
 
  "38",
82
 
  "39",
83
 
  "Disconnect-Request",
84
 
  "Disconnect-ACK",
85
 
  "Disconnect-NAK",
86
 
  "CoF-Request",
87
 
  "CoF-ACK",
88
 
  "CoF-NAK",
89
 
  "46",
90
 
  "47",
91
 
  "48",
92
 
  "49",
93
 
  "IP-Address-Allocate",
94
 
  "IP-Address-Release"
95
 
};
 
41
static int minimal = 0;
 
42
static int do_sort = 0;
 
43
struct timeval start_pcap = {0, 0};
 
44
static rbtree_t *filter_tree = NULL;
 
45
typedef int (*rbcmp)(const void *, const void *);
96
46
 
97
47
static int filter_packet(RADIUS_PACKET *packet)
98
48
{
115
65
                                        fail++;
116
66
                        }
117
67
        }
 
68
 
 
69
 
118
70
        if (fail == 0 && pass != 0) {
119
 
                return 0;
120
 
        }
121
 
 
 
71
                /*
 
72
                 *      Cache authentication requests, as the replies
 
73
                 *      may not match the RADIUS filter.
 
74
                 */
 
75
                if ((packet->code == PW_AUTHENTICATION_REQUEST) ||
 
76
                    (packet->code == PW_ACCOUNTING_REQUEST)) {
 
77
                        rbtree_deletebydata(filter_tree, packet);
 
78
                        
 
79
                        if (!rbtree_insert(filter_tree, packet)) {
 
80
                        oom:
 
81
                                fprintf(stderr, "radsniff: Out of memory\n");
 
82
                                exit(1);
 
83
                        }
 
84
                }
 
85
                return 0;       /* matched */
 
86
        }
 
87
 
 
88
        /*
 
89
         *      Don't create erroneous matches.
 
90
         */
 
91
        if ((packet->code == PW_AUTHENTICATION_REQUEST) ||
 
92
            (packet->code == PW_ACCOUNTING_REQUEST)) {
 
93
                rbtree_deletebydata(filter_tree, packet);
 
94
                return 1;
 
95
        }
 
96
        
 
97
        /*
 
98
         *      Else see if a previous Access-Request
 
99
         *      matched.  If so, also print out the
 
100
         *      matching accept, reject, or challenge.
 
101
         */
 
102
        if ((packet->code == PW_AUTHENTICATION_ACK) ||
 
103
            (packet->code == PW_AUTHENTICATION_REJECT) ||
 
104
            (packet->code == PW_ACCESS_CHALLENGE) ||
 
105
            (packet->code == PW_ACCOUNTING_RESPONSE)) {
 
106
                RADIUS_PACKET *reply;
 
107
 
 
108
                /*
 
109
                 *      This swaps the various fields.
 
110
                 */
 
111
                reply = rad_alloc_reply(packet);
 
112
                if (!reply) goto oom;
 
113
                
 
114
                compare = 1;
 
115
                if (rbtree_finddata(filter_tree, reply)) {
 
116
                        compare = 0;
 
117
                }
 
118
                
 
119
                rad_free(&reply);
 
120
                return compare;
 
121
        }
 
122
        
122
123
        return 1;
123
124
}
124
125
 
 
126
/*
 
127
 *      Bubble goodness
 
128
 */
 
129
static void sort(RADIUS_PACKET *packet)
 
130
{
 
131
        int i, j, size;
 
132
        VALUE_PAIR *vp, *tmp;
 
133
        VALUE_PAIR *array[1024]; /* way more than necessary */
 
134
 
 
135
        size = 0;
 
136
        for (vp = packet->vps; vp != NULL; vp = vp->next) {
 
137
                array[size++] = vp;
 
138
        }
 
139
 
 
140
        if (size == 0) return;
 
141
 
 
142
        for (i = 0; i < size - 1; i++)  {
 
143
                for (j = 0; j < size - 1 - i; j++) {
 
144
                        if (array[j + 1]->attribute < array[j]->attribute)  {
 
145
                                tmp = array[j];         
 
146
                                array[j] = array[j + 1];
 
147
                                array[j + 1] = tmp;
 
148
                        }
 
149
                }
 
150
        }
 
151
 
 
152
        /*
 
153
         *      And put them back again.
 
154
         */
 
155
        vp = packet->vps = array[0];
 
156
        for (i = 1; i < size; i++) {
 
157
                vp->next = array[i];
 
158
                vp = array[i];
 
159
        }
 
160
        vp->next = NULL;
 
161
}
 
162
 
 
163
#define USEC 1000000
 
164
static void tv_sub(struct timeval *end, struct timeval *start,
 
165
                   struct timeval *elapsed)
 
166
{
 
167
        elapsed->tv_sec = end->tv_sec - start->tv_sec;
 
168
        if (elapsed->tv_sec > 0) {
 
169
                elapsed->tv_sec--;
 
170
                elapsed->tv_usec = USEC;
 
171
        } else {
 
172
                elapsed->tv_usec = 0;
 
173
        }
 
174
        elapsed->tv_usec += end->tv_usec;
 
175
        elapsed->tv_usec -= start->tv_usec;
 
176
        
 
177
        if (elapsed->tv_usec >= USEC) {
 
178
                elapsed->tv_usec -= USEC;
 
179
                elapsed->tv_sec++;
 
180
        }
 
181
}
 
182
 
125
183
static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const uint8_t *data)
126
184
{
127
185
        /* Just a counter of how many packets we've had */
137
195
        int size_udp = sizeof(struct udp_header);
138
196
        /* For FreeRADIUS */
139
197
        RADIUS_PACKET *packet;
 
198
        struct timeval elapsed;
140
199
 
141
200
        args = args;            /* -Wunused */
142
201
 
164
223
        packet->data_len = header->len - size_ethernet - size_ip - size_udp;
165
224
 
166
225
        if (!rad_packet_ok(packet, 0)) {
167
 
                librad_perror("Packet");
 
226
                fr_perror("Packet");
 
227
                
 
228
                fprintf(stderr, "\tFrom:    %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
 
229
                fprintf(stderr, "\tTo:      %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
 
230
                fprintf(stderr, "\tType:    %s\n", fr_packet_codes[packet->code]);
 
231
 
168
232
                free(packet);
169
233
                return;
170
234
        }
174
238
         */
175
239
        if (rad_decode(packet, NULL, radius_secret) != 0) {
176
240
                free(packet);
177
 
                librad_perror("decode");
 
241
                fr_perror("decode");
178
242
                return;
179
243
        }
 
244
 
180
245
        if (filter_vps && filter_packet(packet)) {
181
246
                free(packet);
182
247
                DEBUG("Packet number %d doesn't match\n", count++);
183
248
                return;
184
249
        }
 
250
        printf("%s Id %d\t", fr_packet_codes[packet->code], packet->id);
185
251
 
186
252
        /* Print the RADIUS packet */
187
 
        printf("Packet number %d has just been sniffed\n", count++);
188
 
        printf("\tFrom:    %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
189
 
        printf("\tTo:      %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
190
 
        printf("\tType:    %s\n", packet_codes[packet->code]);
191
 
        if (packet->vps != NULL) {
 
253
        printf("%s:%d -> ", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
 
254
        printf("%s:%d", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
 
255
        if (fr_debug_flag) printf("\t(%d packets)", count++);
 
256
 
 
257
        if (!start_pcap.tv_sec) {
 
258
                start_pcap = header->ts;
 
259
        }
 
260
 
 
261
        tv_sub(&header->ts, &start_pcap, &elapsed);
 
262
 
 
263
        printf("\t+%u.%03u", (unsigned int) elapsed.tv_sec,
 
264
               (unsigned int) elapsed.tv_usec / 1000);
 
265
        if (!minimal) printf("\n");
 
266
        if (!minimal && packet->vps) {
 
267
                if (do_sort) sort(packet);
 
268
 
192
269
                vp_printlist(stdout, packet->vps);
193
270
                pairfree(&packet->vps);
194
271
        }
 
272
        printf("\n");
195
273
        fflush(stdout);
196
 
        free(packet);
 
274
 
 
275
        /*
 
276
         *      If we're doing filtering, Access-Requests are cached
 
277
         *      in the filter tree.
 
278
         */
 
279
        if (!filter_vps ||
 
280
            ((packet->code != PW_AUTHENTICATION_REQUEST) &&
 
281
             (packet->code != PW_ACCOUNTING_REQUEST))) {
 
282
                free(packet);
 
283
        }
197
284
}
198
285
 
199
286
static void NEVER_RETURNS usage(int status)
206
293
        fprintf(output, "\t-f filter\tPCAP filter. (default is udp port 1812 or 1813 or 1814)\n");
207
294
        fprintf(output, "\t-h\t\tPrint this help message.\n");
208
295
        fprintf(output, "\t-i interface\tInterface to capture.\n");
 
296
        fprintf(output, "\t-I filename\tRead packets from filename.\n");
 
297
        fprintf(output, "\t-m\t\tPrint packet headers only, not contents.\n");
209
298
        fprintf(output, "\t-p port\tList for packets on port.\n");
210
299
        fprintf(output, "\t-r filter\tRADIUS attribute filter.\n");
211
300
        fprintf(output, "\t-s secret\tRADIUS secret.\n");
212
 
        fprintf(output, "\t-X\t\tPrint out debugging information.\n");
 
301
        fprintf(output, "\t-S\t\tSort attributes in the packet.  Used to compare server results.\n");
 
302
        fprintf(output, "\t-x\t\tPrint out debugging information.\n");
213
303
        exit(status);
214
304
}
215
305
 
224
314
        char buffer[1024];
225
315
        char *pcap_filter = NULL;
226
316
        char *radius_filter = NULL;
 
317
        char *filename = NULL;
227
318
        int packet_count = -1;          /* how many packets to sniff */
228
319
        int opt;
229
320
        FR_TOKEN parsecode;
234
325
        dev = pcap_lookupdev(errbuf);
235
326
 
236
327
        /* Get options */
237
 
        while ((opt = getopt(argc, argv, "c:d:f:hi:p:r:s:X")) != EOF) {
 
328
        while ((opt = getopt(argc, argv, "c:d:f:hi:I:mp:r:s:SxX")) != EOF) {
238
329
                switch (opt)
239
330
                {
240
331
                case 'c':
256
347
                case 'i':
257
348
                        dev = optarg;
258
349
                        break;
 
350
                case 'I':
 
351
                        filename = optarg;
 
352
                        break;
 
353
                case 'm':
 
354
                        minimal = 1;
 
355
                        break;
259
356
                case 'p':
260
357
                        port = atoi(optarg);
261
358
                        break;
265
362
                case 's':
266
363
                        radius_secret = optarg;
267
364
                        break;
268
 
                case 'X':
269
 
                        debug_flag = 1;
 
365
                case 'S':
 
366
                        do_sort = 1;
 
367
                        break;
 
368
                case 'x':
 
369
                case 'X':       /* for backwards compatibility */
 
370
                        fr_debug_flag++;
270
371
                        break;
271
372
                default:
272
373
                        usage(1);
280
381
        }
281
382
 
282
383
        if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
283
 
                librad_perror("radsniff");
 
384
                fr_perror("radsniff");
284
385
                return 1;
285
386
        }
286
387
 
287
388
        if (radius_filter) {
288
389
                parsecode = userparse(radius_filter, &filter_vps);
289
390
                if (parsecode == T_OP_INVALID) {
290
 
                        fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\": %s\n", optarg, librad_errstr);
 
391
                        fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\": %s\n", radius_filter, fr_strerror());
291
392
                        exit(1);
292
393
                }
293
394
                if (!filter_vps) {
294
 
                        fprintf(stderr, "radsniff: Empty RADIUS filter \"%s\"\n", optarg);
 
395
                        fprintf(stderr, "radsniff: Empty RADIUS filter \"%s\"\n", radius_filter);
 
396
                        exit(1);
 
397
                }
 
398
 
 
399
                filter_tree = rbtree_create((rbcmp) fr_packet_cmp,
 
400
                                            free, 0);
 
401
                if (!filter_tree) {
 
402
                        fprintf(stderr, "radsniff: Failed creating filter tree\n");
295
403
                        exit(1);
296
404
                }
297
405
        }
300
408
        pcap_lookupnet(dev, &netp, &maskp, errbuf);
301
409
 
302
410
        /* Print device to the user */
303
 
        printf("Device: [%s]\n", dev);
304
 
        if (packet_count > 0) {
305
 
                printf("Num of packets: [%d]\n", packet_count);
306
 
        }
307
 
        printf("PCAP filter: [%s]\n", pcap_filter);
308
 
        if (filter_vps != NULL) {
309
 
                printf("RADIUS filter:\n");
310
 
                vp_printlist(stdout, filter_vps);
311
 
        }
312
 
        printf("RADIUS secret: [%s]\n", radius_secret);
 
411
        if (fr_debug_flag) {
 
412
                if (dev) printf("Device: [%s]\n", dev);
 
413
                if (packet_count > 0) {
 
414
                        printf("Num of packets: [%d]\n",
 
415
                               packet_count);
 
416
                }
 
417
                printf("PCAP filter: [%s]\n", pcap_filter);
 
418
                if (filter_vps) {
 
419
                        printf("RADIUS filter:\n");
 
420
                        vp_printlist(stdout, filter_vps);
 
421
                }
 
422
                printf("RADIUS secret: [%s]\n", radius_secret);
 
423
        }
313
424
 
314
425
        /* Open the device so we can spy */
315
 
        descr = pcap_open_live(dev, SNAPLEN, 1, 0, errbuf);
 
426
        if (filename) {
 
427
                descr = pcap_open_offline(filename, errbuf);
 
428
        } else {
 
429
                descr = pcap_open_live(dev, SNAPLEN, 1, 0, errbuf);
 
430
        }
316
431
        if (descr == NULL)
317
432
        {
318
433
                printf("radsniff: pcap_open_live failed (%s)\n", errbuf);
335
450
        pcap_loop(descr, packet_count, got_packet, NULL);
336
451
        pcap_close(descr);
337
452
 
338
 
        printf("Done sniffing\n");
339
 
        fflush(stdout);
 
453
        if (filter_tree) rbtree_free(filter_tree);
 
454
 
 
455
        DEBUG("Done sniffing\n");
340
456
        return 0;
341
457
}