1 /* $Id: raddump.c,v 1.2 2004/09/22 15:15:52 iscjonm Exp $
2  *
3  * Copyright (C) 2004-2005 The Trustees of the University of Pennsylvania
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <time.h>
33 #include <unistd.h>
34 
35 #ifdef HAVE_NET_IF_H
36 #  include <net/if.h>
37 #endif /* HAVE_NET_IF_H */
38 
39 #ifdef HAVE_NET_ETHERNET_H
40 #  include <net/ethernet.h>
41 #else /* ! HAVE_NET_ETHERNET_H */
42 #  ifdef HAVE_NETINET_IF_ETHER_H
43 #    include <netinet/if_ether.h>
44 #  endif /* HAVE_NETINET_IF_ETHER_H */
45 #endif /* HAVE_NET_ETHERNET_H */
46 
47 #include <netinet/in_systm.h>
48 #include <netinet/in.h>
49 #include <netinet/ip.h>
50 #include <netinet/udp.h>
51 #include <netdb.h>
52 
53 #ifdef HAVE_PCAP_H
54 /* for tcpdump formatting */
55 #include <pcap.h>
56 #endif /* HAVE_PCAP_H */
57 
58 #include "vlan.h"
59 #include "pktrecord.h"
60 #include "radius.h"
61 
62 int verbose = 0;
63 int lookup_hostnames = 1;
64 int use_short_hostnames = 0;
65 
66 static void usage(char *progname);
67 static void parse_cmdline(int argc, char *argv[]);
68 
main(int argc,char ** argv)69 int main(int argc, char **argv) {
70 
71   struct prec_handle *ph = NULL;
72   struct pktrecord p;
73   struct ether_header eh;
74   struct vlan_hdr vh;
75   int tagged_vlan_found = 0;
76   struct ip iph;
77   struct udphdr uh;
78   unsigned short int udp_srcport;
79   unsigned short int udp_dstport;
80   struct radius_hdr rh;
81   struct radius_attr *ra;
82   unsigned int offs;
83   struct timeval tstamp;
84   struct tm localt;
85   int pkts_in = 0;
86   int rh_offs = 0;
87 
88   char srchost[256];
89   char dsthost[256];
90   char vlan_id_string[256];
91 
92   rad_init();
93 
94   parse_cmdline(argc, argv);
95 
96   if (!prec_init(&ph)) {
97     fprintf(stderr,"Unrecognized packet trace format\n");
98     exit(EXIT_FAILURE);
99   }
100   if (!prec_is_eth(ph)) {
101     fprintf(stderr,"These aren't Ethernet packets!\n");
102     exit(EXIT_FAILURE);
103   }
104   pkts_in = 0;
105 
106   memset(&p, 0, sizeof(p));
107 
108   while(prec_next_packet(ph,&p)) {
109     pkts_in++;
110 
111     offs = 0;
112 
113     /* locate Ethernet header */
114     if (p.included_len < offs + sizeof(eh)) continue;
115     memcpy(&eh, p.pkt_data + offs, sizeof(eh));
116 
117     /* check for 802.1q VLAN tags */
118     tagged_vlan_found = 0;
119     vlan_id_string[0] = '\0';
120     switch(ntohs(eh.ether_type)) {
121       case ETHERTYPE_IP:
122 	offs += sizeof(eh);
123 	break;
124       case ETHERTYPE_VLAN:
125 	if (p.included_len < offs + sizeof(vh)) continue;
126 	memcpy(&vh, p.pkt_data + offs, sizeof(vh));
127 	tagged_vlan_found = 1;
128 	if (ntohs(vh.ether_type) != ETHERTYPE_IP) continue;
129 	offs += sizeof(vh);
130 	break;
131       default:
132 	continue;
133     }
134 
135     /* locate IP header */
136     if (p.included_len < offs + sizeof(iph)) continue;
137     memcpy(&iph, p.pkt_data + offs, sizeof(iph));
138     offs += iph.ip_hl * 4; /* in case we have IP options */
139 
140     /* get UDP header */
141     if (iph.ip_p != IPPROTO_UDP ||
142 	p.included_len < offs + sizeof(uh)) continue;
143     memcpy(&uh, p.pkt_data + offs, sizeof(uh));
144     offs += sizeof(uh);
145 
146     /* find RADIUS header */
147 #ifdef HAVE_STRUCT_UDPHDR_UH_SPORT
148     udp_srcport = ntohs(uh.uh_sport);
149     udp_dstport = ntohs(uh.uh_dport);
150 #else
151 #ifdef HAVE_STRUCT_UDPHDR_SOURCE
152     udp_srcport = ntohs(uh.source);
153     udp_dstport = ntohs(uh.dest);
154 #else
155 #error "Don't know how to interpret the struct udphdr on your system"
156 #endif
157 #endif
158     if (udp_dstport != 1645 && udp_srcport != 1645 &&
159 	udp_dstport != 1812 && udp_srcport != 1812 &&
160 	udp_dstport != 1646 && udp_srcport != 1646 &&
161 	udp_dstport != 1813 && udp_srcport != 1813) continue;
162     if (p.included_len < offs + sizeof(rh)) continue;
163     memcpy(&rh, p.pkt_data + offs, sizeof(rh));
164     rh_offs = offs;
165     offs += sizeof(rh);
166 
167     tstamp.tv_sec = p.ts_secs;
168     tstamp.tv_usec = p.ts_usecs;
169     localtime_r((time_t *)(&tstamp.tv_sec), &localt);
170 
171     /* by default, print IP addresses */
172     sprintf(srchost,"%s",inet_ntoa(iph.ip_src));
173     sprintf(dsthost,"%s",inet_ntoa(iph.ip_dst));
174     if (lookup_hostnames) {
175       struct hostent *he = NULL;
176       if ((he = gethostbyaddr((char *)&(iph.ip_src),
177 			      sizeof(struct in_addr),
178 			      AF_INET)) != NULL) {
179 	strncpy(srchost,he->h_name,sizeof(srchost));
180 	if (use_short_hostnames) {
181 	  char *cp = srchost;
182 	  while (*cp != '.' && *cp != '\0') cp++;
183 	  if (*cp == '.') *cp = '\0';
184 	}
185       }
186       if ((he = gethostbyaddr((char *)&(iph.ip_dst),
187 			      sizeof(struct in_addr),
188 			      AF_INET)) != NULL) {
189 	strncpy(dsthost,he->h_name,sizeof(dsthost));
190 	if (use_short_hostnames) {
191 	  char *cp = dsthost;
192 	  while (*cp != '.' && *cp != '\0') cp++;
193 	  if (*cp == '.') *cp = '\0';
194 	}
195       }
196     }
197 
198     if (tagged_vlan_found) {
199       sprintf(vlan_id_string,"vlan %d ",VLAN_ID(&vh));
200     }
201 
202     printf("%02d:%02d:%02d.%06d radius %s%s:%d > %s:%d %s %u\n",
203 	   localt.tm_hour, localt.tm_min, localt.tm_sec,
204 	   tstamp.tv_usec,
205 	   vlan_id_string,
206 	   srchost, udp_srcport,
207 	   dsthost, udp_dstport,
208 	   rad_code_str(rh.code),
209 	   ntohs(rh.len) - (unsigned short)sizeof(rh));
210 
211     if (verbose >= 1) {
212       while(offs < p.included_len && offs < rh_offs + ntohs(rh.len)) {
213 	if (p.included_len < offs + 2) break;
214 	ra = (struct radius_attr *)(p.pkt_data + offs);
215 	offs += ra->len;
216 
217 	printf("  %s = ",rad_attr_name(ra));
218 	rad_print_attr_val(ra);
219 	printf("\n");
220       }
221     }
222   }
223   prec_close(ph);
224   exit(EXIT_SUCCESS);
225 }
226 
usage(char * progname)227 static void usage(char *progname) {
228   (void)printf("usage: %s [-?vsn]\n",progname);
229   (void)printf("  -?: this help\n");
230   (void)printf("  -v: more verbose (multiple -v allowed)\n");
231   (void)printf("  -n: do not do reverse DNS lookups\n");
232   (void)printf("  -s: use short hostnames\n");
233 }
234 
parse_cmdline(int argc,char * argv[])235 static void parse_cmdline(int argc, char *argv[]) {
236   char *optstring = "?vsn";
237   int c;
238   int args_processed = 0;
239   int args_expected = 0;
240 
241   while ((c = getopt(argc,argv,optstring)) != EOF) {
242     switch (c) {
243     case '?':
244       usage(argv[0]);
245       exit(EXIT_SUCCESS);
246       break;
247     case 'v':
248       verbose++;
249       break;
250     case 'n':
251       lookup_hostnames = 0;
252       break;
253     case 's':
254       use_short_hostnames = 1;
255       break;
256     default:
257       (void)fprintf(stderr,"%s: unknown option '-%c'\n",argv[0],c);
258       usage(argv[0]);
259       exit(EXIT_FAILURE);
260     }
261   }
262   while(args_processed < args_expected) {
263     if (optind >= argc) {
264       fprintf(stderr,"%s: missing args\n",argv[0]);
265       usage(argv[0]);
266       exit(EXIT_FAILURE);
267     }
268     switch(args_processed) {
269     default:
270       break;
271     }
272     optind++;
273     args_processed++;
274   }
275   if (argc > optind) {
276     fprintf(stderr,"%s: too many arguments\n",argv[0]);
277     usage(argv[0]);
278     exit(EXIT_FAILURE);
279   }
280 }
281