2 * radsniff.c Display the RADIUS traffic on the network.
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2006 The FreeRADIUS server project
21 * Copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/autoconf.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
38 #include <freeradius-devel/radpaths.h>
39 #include <freeradius-devel/conf.h>
40 #include <freeradius-devel/libradius.h>
41 #include <freeradius-devel/radsniff.h>
43 static const char *radius_secret = "testing123";
44 static VALUE_PAIR *filter_vps = NULL;
46 static const char *packet_codes[] = {
52 "Accounting-Response",
68 "Resource-Free-Request",
69 "Resource-Free-Response",
70 "Resource-Query-Request",
71 "Resource-Query-Response",
72 "Alternate-Resource-Reclaim-Request",
74 "NAS-Reboot-Response",
97 "IP-Address-Allocate",
102 * Stolen from rad_recv() in ../lib/radius.c
104 static RADIUS_PACKET *init_packet(const uint8_t *data, size_t data_len)
106 RADIUS_PACKET *packet;
109 * Allocate the new request data structure
111 if ((packet = malloc(sizeof(*packet))) == NULL) {
112 librad_log("out of memory");
115 memset(packet, 0, sizeof(*packet));
118 packet->data_len = data_len;
120 if (!rad_packet_ok(packet)) {
126 * Explicitely set the VP list to empty.
133 static int filter_packet(RADIUS_PACKET *packet)
135 VALUE_PAIR *check_item;
137 unsigned int pass, fail;
141 for (vp = packet->vps; vp != NULL; vp = vp->next) {
142 for (check_item = filter_vps;
144 check_item = check_item->next)
145 if ((check_item->attribute == vp->attribute)
146 && (check_item->operator != T_OP_SET)) {
147 compare = paircmp(check_item, vp);
154 if (fail == 0 && pass != 0) {
161 static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const uint8_t *packet)
163 /* Just a counter of how many packets we've had */
164 static int count = 1;
165 /* Define pointers for packet's attributes */
166 const struct ethernet_header *ethernet; /* The ethernet header */
167 const struct ip_header *ip; /* The IP header */
168 const struct udp_header *udp; /* The UDP header */
169 const uint8_t *payload; /* Packet payload */
170 /* And define the size of the structures we're using */
171 int size_ethernet = sizeof(struct ethernet_header);
172 int size_ip = sizeof(struct ip_header);
173 int size_udp = sizeof(struct udp_header);
175 RADIUS_PACKET *request;
177 args = args; /* -Wunused */
179 /* Define our packet's attributes */
180 ethernet = (const struct ethernet_header*)(packet);
181 ip = (const struct ip_header*)(packet + size_ethernet);
182 udp = (const struct udp_header*)(packet + size_ethernet + size_ip);
183 payload = (const uint8_t *)(packet + size_ethernet + size_ip + size_udp);
185 /* Read the RADIUS packet structure */
186 request = init_packet(payload, header->len - size_ethernet - size_ip - size_udp);
187 if (request == NULL) {
188 librad_perror("check");
191 request->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
192 request->src_port = ntohs(udp->udp_sport);
193 request->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
194 request->dst_port = ntohs(udp->udp_dport);
197 * Decode the data without bothering to check the signatures.
199 if (rad_decode(request, NULL, radius_secret) != 0) {
200 librad_perror("decode");
203 if (filter_vps && filter_packet(request)) {
204 /* printf("Packet number %d doesn't match\n", count++); */
208 /* Print the RADIUS packet */
209 printf("Packet number %d has just been sniffed\n", count++);
210 printf("\tFrom: %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
211 printf("\tTo: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
212 printf("\tType: %s\n", packet_codes[request->code]);
213 if (request->vps != NULL) {
214 vp_printlist(stdout, request->vps);
215 pairfree(&request->vps);
220 static void NEVER_RETURNS usage(int status)
222 FILE *output = status ? stderr : stdout;
223 fprintf(output, "usage: radsniff [options]\n");
224 fprintf(output, "options:\n");
225 fprintf(output, "\t-c count\tNumber of packets to capture.\n");
226 fprintf(output, "\t-d directory\tDirectory where the dictionaries are found\n");
227 fprintf(output, "\t-f filter\tPCAP filter. (default is udp port 1812 or 1813 or 1814)\n");
228 fprintf(output, "\t-h\t\tPrint this help message.\n");
229 fprintf(output, "\t-i interface\tInterface to capture.\n");
230 fprintf(output, "\t-p port\tList for packets on port.\n");
231 fprintf(output, "\t-r filter\tRADIUS attribute filter.\n");
232 fprintf(output, "\t-s secret\tRADIUS secret.\n");
236 int main(int argc, char *argv[])
238 char *dev; /* sniffing device */
239 char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
240 pcap_t *descr; /* sniff handler */
241 struct bpf_program fp; /* hold compiled program */
242 bpf_u_int32 maskp; /* subnet mask */
243 bpf_u_int32 netp; /* ip */
245 char *pcap_filter = NULL;
246 char *radius_filter = NULL;
247 int packet_count = -1; /* how many packets to sniff */
249 LRAD_TOKEN parsecode;
250 const char *radius_dir = RADIUS_DIR;
254 dev = pcap_lookupdev(errbuf);
257 while ((opt = getopt(argc, argv, "c:d:f:hi:p:r:s:")) != EOF) {
261 packet_count = atoi(optarg);
262 if (packet_count <= 0) {
263 fprintf(stderr, "radsniff: Invalid number of packets \"%s\"\n", optarg);
271 pcap_filter = optarg;
283 radius_filter = optarg;
284 parsecode = userparse(radius_filter, &filter_vps);
285 if (parsecode == T_OP_INVALID || filter_vps == NULL) {
286 fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\"\n", optarg);
291 radius_secret = optarg;
299 pcap_filter = buffer;
300 snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d",
301 port, port + 1, port + 2);
304 if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
305 librad_perror("radsniff");
309 pcap_lookupnet(dev, &netp, &maskp, errbuf);
311 /* Print device to the user */
312 printf("Device: [%s]\n", dev);
313 if (packet_count > 0) {
314 printf("Num of packets: [%d]\n", packet_count);
316 printf("PCAP filter: [%s]\n", pcap_filter);
317 if (filter_vps != NULL) {
318 printf("RADIUS filter:\n");
319 vp_printlist(stdout, filter_vps);
321 printf("RADIUS secret: [%s]\n", radius_secret);
323 /* Open the device so we can spy */
324 descr = pcap_open_live(dev, SNAPLEN, 1, 0, errbuf);
327 printf("radsniff: pcap_open_live failed (%s)\n", errbuf);
331 /* Apply the rules */
332 if( pcap_compile(descr, &fp, pcap_filter, 0, netp) == -1)
334 printf("radsniff: pcap_compile failed\n");
337 if (pcap_setfilter(descr, &fp) == -1)
339 printf("radsniff: pcap_setfilter failed\n");
343 /* Now we can set our callback function */
344 pcap_loop(descr, packet_count, got_packet, NULL);
347 printf("Done sniffing\n");