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