1: /*
2: * Copyright (c) 2004 Rinet Corp., Novosibirsk, Russia
3: *
4: * Redistribution and use in source forms, with and without modification,
5: * are permitted provided that this entire comment appears intact.
6: *
7: * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
8: */
9:
10: #ifdef HAVE_CONFIG_H
11: #include <config.h>
12: #endif
13:
14: #include <sys/param.h>
15: #include <sys/types.h>
16: #include <sys/socket.h>
17: #include <netinet/in.h>
18: #include <netinet/in_systm.h>
19: #include <netinet/ip.h>
20: #include <netinet/ip_icmp.h>
21: #include <netinet/udp.h>
22: #include <netinet/tcp.h>
23: #ifdef INET6
24: #include <netinet/ip6.h>
25: #include <netinet/icmp6.h>
26: #endif
27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <string.h>
30: #include <time.h>
31: #include <netdb.h>
32: #include <pthread.h>
33:
34: #include "cisco_netflow.h"
35: #include "trafshow.h"
36: #include "session.h"
37: #include "netstat.h"
38: #include "show_dump.h"
39: #include "addrtoname.h"
40:
41:
42: static void read_netflow(SESSION *sd, const unsigned char *data, int len);
43: static PCAP_HANDLER *match_feeder(PCAP_HANDLER *ph_list, const struct sockaddr *sa);
44: static void parse_netflow(PCAP_HANDLER *ph, const unsigned char *data, int len);
45: static char *get_name(const struct sockaddr *sa, char *dst, int size);
46: static void fprint_tcpflags(FILE *fp, int flags);
47: static void fprint_tos(FILE *fp, int tos);
48: static void dump_netflow_v1(const CNF_DATA_V1 *data);
49: static void dump_netflow_v5(const CNF_DATA_V5 *data);
50: static void dump_netflow_v7(const CNF_DATA_V7 *data);
51:
52: int
53: cisco_netflow_init(ph_list, port)
54: PCAP_HANDLER **ph_list;
55: int port;
56: {
57: SESSION *sd;
58: int sock, on = 1;
59: socklen_t slen;
60: static struct sockaddr_in sin; /* why static? */
61:
62: if (!ph_list) return -1;
63:
64: memset(&sin, 0, sizeof(sin));
65: sin.sin_family = AF_INET;
66: sin.sin_port = htons(port);
67:
68: if ((sd = session_open(-1, 0, DataSequence)) == 0) {
69: perror("session_open");
70: return -1;
71: }
72: sock = session_sock(sd);
73:
74: slen = sizeof(on);
75: #ifdef SO_REUSEPORT
76: if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, slen) < 0) {
77: perror("setsockopt SO_REUSEPORT");
78: return -1;
79: }
80: #elif SO_REUSEADDR
81: if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, slen) < 0) {
82: perror("setsockopt SO_REUSEADDR");
83: return -1;
84: }
85: #endif
86: slen = sizeof(sin);
87: if (bind(sock, (struct sockaddr *)&sin, slen) < 0) {
88: perror("bind");
89: return -1;
90: }
91:
92: session_setcallback(sd, 0, 0, read_netflow);
93: session_setcookie(sd, ph_list);
94: return 0;
95: }
96:
97: static PCAP_HANDLER *
98: match_feeder(ph, sa)
99: PCAP_HANDLER *ph;
100: const struct sockaddr *sa;
101: {
102: const pcap_addr_t *ap;
103:
104: if (!sa) return 0;
105:
106: for (; ph; ph = ph->next) {
107: if (ph->pcap) /* skip pcap devices */
108: continue;
109:
110: for (ap = ph->addr; ap; ap = ap->next) {
111: if (!ap->addr || ap->addr->sa_family != sa->sa_family)
112: continue;
113:
114: if (ap->addr->sa_family == AF_INET) {
115: if (!memcmp(&((struct sockaddr_in *)ap->addr)->sin_addr,
116: &((struct sockaddr_in *)sa)->sin_addr,
117: sizeof(struct in_addr)))
118: return ph;
119: }
120: #ifdef INET6
121: else if (ap->addr->sa_family == AF_INET6) {
122: if (!memcmp(&((struct sockaddr_in6 *)ap->addr)->sin6_addr,
123: &((struct sockaddr_in6 *)sa)->sin6_addr,
124: sizeof(struct in6_addr)))
125: return ph;
126: }
127: #endif
128: }
129: }
130: return 0;
131: }
132:
133: static char *
134: get_name(sa, dst, size)
135: const struct sockaddr *sa;
136: char *dst;
137: int size;
138: {
139: struct hostent *hp = 0;
140:
141: if (!sa) return 0;
142:
143: if (sa->sa_family == AF_INET) {
144: hp = gethostbyaddr((char *)&((struct sockaddr_in *)sa)->sin_addr,
145: sizeof(struct in_addr), AF_INET);
146: }
147: #ifdef INET6
148: else if (sa->sa_family == AF_INET6) {
149: hp = gethostbyaddr((char *)&((struct sockaddr_in6 *)sa)->sin6_addr,
150: sizeof(struct in6_addr), AF_INET6);
151: }
152: #endif
153: if (hp) {
154: int i;
155: for (i = 0; i < size-1; i++) {
156: if (hp->h_name[i] == '\0' || hp->h_name[i] == '.')
157: break;
158: dst[i] = hp->h_name[i];
159: }
160: dst[i] = '\0';
161: return dst;
162: }
163: return 0;
164: }
165:
166: static void
167: read_netflow(sd, data, len)
168: SESSION *sd;
169: const unsigned char *data;
170: int len;
171: {
172: const struct sockaddr *from;
173: PCAP_HANDLER *ph, **ph_list = (PCAP_HANDLER **)session_cookie(sd);
174:
175: /* sanity check */
176: if (!ph_list || !data || len < sizeof(CNF_HDR_V1))
177: return;
178:
179: if ((from = session_from(sd)) == 0)
180: return; /* should not happen */
181:
182: if ((ph = match_feeder(*ph_list, from)) == 0) { /* insert new one */
183: int cnt = 0;
184: PCAP_HANDLER *ph_prev = 0;
185: char buf[256];
186: pcap_addr_t *ap;
187:
188: for (ph = *ph_list; ph; ph = ph->next) {
189: if (!ph->pcap) cnt++;
190: ph_prev = ph;
191: }
192:
193: if ((ph = (PCAP_HANDLER *)malloc(sizeof(PCAP_HANDLER))) == 0) {
194: perror("malloc");
195: return;
196: }
197: memset(ph, 0, sizeof(PCAP_HANDLER));
198:
199: ph->masklen = aggregate;
200: if (!get_name(from, buf, sizeof(buf)))
201: sprintf(buf, "netflow%d", cnt);
202: ph->name = strdup(buf);
203:
204: sprintf(buf, "Netflow V%d", ntohs(((CNF_HDR_V1 *)data)->version));
205: ph->descr = strdup(buf);
206:
207: if ((ap = (pcap_addr_t *)malloc(sizeof(struct pcap_addr))) != 0) {
208: memset(ap, 0, sizeof(struct pcap_addr));
209: if ((ap->addr = (struct sockaddr *)malloc(sizeof(struct sockaddr))) == 0) {
210: perror("malloc");
211: return;
212: }
213: memcpy(ap->addr, from, sizeof(struct sockaddr));
214: }
215: ph->addr = ap;
216:
217: if ((ph->ns_mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t))) == 0) {
218: perror("malloc");
219: return;
220: }
221: pthread_mutex_init(ph->ns_mutex, 0);
222:
223: ph->prev = ph_prev;
224: if (ph_prev)
225: ph_prev->next = ph;
226: else *ph_list = ph;
227: }
228:
229: parse_netflow(ph, data, len);
230: }
231:
232: static void
233: parse_netflow(ph, data, len)
234: PCAP_HANDLER *ph;
235: const unsigned char *data;
236: int len;
237: {
238: struct timeval now;
239: int version, counter, msec, hdrlen, dump_it;
240: CNF_HDR_V1 *v1h;
241: CNF_HDR_V5 *v5h;
242: CNF_HDR_V7 *v7h;
243: CNF_DATA_V1 *v1d = 0;
244: CNF_DATA_V5 *v5d = 0;
245: CNF_DATA_V7 *v7d = 0;
246: NETSTAT ns;
247:
248: v1h = (CNF_HDR_V1 *)data;
249: if (!v1h || len < sizeof(CNF_HDR_V1))
250: return;
251:
252: version = ntohs(v1h->version);
253: counter = ntohs(v1h->counter);
254: if (version == 1) {
255: v1d = (CNF_DATA_V1 *)(data + sizeof(CNF_HDR_V1));
256: len -= sizeof(sizeof(CNF_HDR_V1));
257: len /= sizeof(CNF_DATA_V1);
258: } else if (version == 5) {
259: v5h = (CNF_HDR_V5 *)data;
260: v5d = (CNF_DATA_V5 *)(data + sizeof(CNF_HDR_V5));
261: len -= sizeof(sizeof(CNF_HDR_V5));
262: len /= sizeof(CNF_DATA_V5);
263: } else if (version == 7) {
264: v7h = (CNF_HDR_V7 *)data;
265: v7d = (CNF_DATA_V7 *)(data + sizeof(CNF_HDR_V7));
266: len -= sizeof(sizeof(CNF_HDR_V7));
267: len /= sizeof(CNF_DATA_V7);
268: } else return;
269:
270: gettimeofday(&now, 0);
271:
272: while (counter-- > 0 && len-- > 0) {
273: struct ip_address *src = &ns.ip_src_addr;
274: struct ip_address *dst = &ns.ip_dst_addr;
275:
276: memset(&ns, 0, sizeof(NETSTAT));
277: ns.ip_ver = 4; /* XXX what about IPv6? */
278: ns.mtime = now;
279: msec = 0;
280: dump_it = 0;
281:
282: if (version == 1 && v1d) {
283: ns.ip_proto = v1d->proto;
284:
285: src->ip_addr.s_addr = v1d->src_addr;
286: src->ip_port = v1d->src_port;
287:
288: dst->ip_addr.s_addr = v1d->dst_addr;
289: dst->ip_port = v1d->dst_port;
290:
291: ns.pkt_cnt = ntohl(v1d->dpkts);
292: ns.pkt_len = ntohl(v1d->doctets);
293:
294: msec = ntohl(v1d->lasttime) - ntohl(v1d->firsttime);
295:
296: } else if (version == 5 && v5d) {
297: ns.ip_proto = v5d->proto;
298:
299: src->ip_addr.s_addr = v5d->src_addr;
300: src->ip_port = v5d->src_port;
301:
302: dst->ip_addr.s_addr = v5d->dst_addr;
303: dst->ip_port = v5d->dst_port;
304:
305: ns.pkt_cnt = ntohl(v5d->dpkts);
306: ns.pkt_len = ntohl(v5d->doctets);
307:
308: msec = ntohl(v5d->lasttime) - ntohl(v5d->firsttime);
309:
310: } else if (version == 7 && v7d) {
311: ns.ip_proto = v7d->proto;
312:
313: src->ip_addr.s_addr = v7d->src_addr;
314: src->ip_port = v7d->src_port;
315:
316: dst->ip_addr.s_addr = v7d->dst_addr;
317: dst->ip_port = v7d->dst_port;
318:
319: ns.pkt_cnt = ntohl(v7d->dpkts);
320: ns.pkt_len = ntohl(v7d->doctets);
321:
322: msec = ntohl(v7d->lasttime) - ntohl(v7d->firsttime);
323: }
324:
325: /* suggest data length (dirty fake) */
326: hdrlen = sizeof(struct ip);
327: switch (ns.ip_proto) {
328: case IPPROTO_TCP:
329: hdrlen += sizeof(struct tcphdr);
330: break;
331: case IPPROTO_UDP:
332: hdrlen += sizeof(struct udphdr);
333: break;
334: case IPPROTO_ICMP:
335: hdrlen += sizeof(struct icmp);
336: break;
337: }
338: hdrlen *= ns.pkt_cnt;
339: if (ns.pkt_len >= hdrlen)
340: ns.data_len = ns.pkt_len - hdrlen;
341:
342: if (msec > 0) {
343: ns.pkt_cnt_rate = ns.pkt_cnt * 1000 / msec;
344: ns.pkt_len_rate = ns.pkt_len * 1000 / msec;
345: ns.data_len_rate = ns.data_len * 1000 / msec;
346: }
347:
348: pcap_save(ph, &ns);
349:
350: if (cisco_netflow_dump && ph->name &&
351: !strcmp(cisco_netflow_dump, ph->name) &&
352: netstat_match(&ns, dump_match)) {
353: dump_it++;
354: }
355: if (version == 1 && v1d) {
356: if (dump_it) dump_netflow_v1(v1d);
357: v1d++;
358: } else if (version == 5 && v5d) {
359: if (dump_it) dump_netflow_v5(v5d);
360: v5d++;
361: } else if (version == 7 && v7d) {
362: if (dump_it) dump_netflow_v7(v7d);
363: v7d++;
364: }
365: }
366: }
367:
368: static void
369: fprint_tcpflags(fp, flags)
370: FILE *fp;
371: int flags;
372: {
373: fprintf(fp, "TCPflags: %02x", flags);
374:
375: if (flags & 0x01) fprintf(fp, " FIN");
376: if (flags & 0x02) fprintf(fp, " SYN");
377: if (flags & 0x04) fprintf(fp, " RST");
378: if (flags & 0x08) fprintf(fp, " PUSH");
379: if (flags & 0x10) fprintf(fp, " ACK");
380: if (flags & 0x20) fprintf(fp, " URG");
381:
382: fprintf(fp, "\n");
383: }
384:
385: static void
386: fprint_tos(fp, tos)
387: FILE *fp;
388: int tos;
389: {
390: fprintf(fp, "TOS: %02x", tos);
391:
392: switch (tos & 0xe0) { /* precedence bits */
393: case 0xe0: fprintf(fp, " NETCONTROL"); break;
394: case 0xc0: fprintf(fp, " INTERNETCONTROL"); break;
395: case 0xa0: fprintf(fp, " CRITIC_ECP"); break;
396: case 0x80: fprintf(fp, " FLASHOVERRIDE"); break;
397: case 0x60: fprintf(fp, " FLASH"); break;
398: case 0x40: fprintf(fp, " IMMEDIATE"); break;
399: case 0x20: fprintf(fp, " PRIORITY"); break;
400: }
401: tos &= 0x1e; /* type of service bits */
402: if (tos & 0x10) fprintf(fp, " LOWDELAY");
403: if (tos & 0x08) fprintf(fp, " THROUGHPUT");
404: if (tos & 0x04) fprintf(fp, " RELIABILITY");
405: if (tos & 0x02) fprintf(fp, " LOWCOST");
406:
407: fprintf(fp, "\n");
408: }
409:
410: static void
411: dump_netflow_v1(dp)
412: const CNF_DATA_V1 *dp;
413: {
414: FILE *fp;
415:
416: if (!dump_file || (fp = fopen(dump_file, "a")) == 0)
417: return;
418:
419: fprintf(fp, "\nNetflow: V1\n");
420: fprintf(fp, "SrcAddr: %s\n", intoa(dp->src_addr));
421: fprintf(fp, "DstAddr: %s\n", intoa(dp->dst_addr));
422: fprintf(fp, "NextHop: %s\n", intoa(dp->nexthop));
423: fprintf(fp, "InputIf: %d\n", (int)ntohs(dp->ifin));
424: fprintf(fp, "OutputIf: %d\n", (int)ntohs(dp->ifout));
425: fprintf(fp, "Packets: %u\n", (u_int32_t)ntohl(dp->dpkts));
426: fprintf(fp, "Octets: %u\n", (u_int32_t)ntohl(dp->doctets));
427: fprintf(fp, "First: %u\n", (u_int32_t)ntohl(dp->firsttime));
428: fprintf(fp, "Last: %u\n", (u_int32_t)ntohl(dp->lasttime));
429: if (dp->proto == IPPROTO_TCP) {
430: fprintf(fp, "SrcPort: %s\n", tcpport_string(ntohs(dp->src_port)));
431: fprintf(fp, "DstPort: %s\n", tcpport_string(ntohs(dp->dst_port)));
432: } else if (dp->proto == IPPROTO_UDP) {
433: fprintf(fp, "SrcPort: %s\n", udpport_string(ntohs(dp->src_port)));
434: fprintf(fp, "DstPort: %s\n", udpport_string(ntohs(dp->dst_port)));
435: } else {
436: fprintf(fp, "SrcPort: %d\n", (int)ntohs(dp->src_port));
437: fprintf(fp, "DstPort: %d\n", (int)ntohs(dp->dst_port));
438: }
439: fprintf(fp, "Protocol: %s\n", ipproto_string(dp->proto));
440: fprint_tos(fp, dp->tos);
441: fprint_tcpflags(fp, dp->flags);
442:
443: (void)fclose(fp);
444: }
445:
446: static void
447: dump_netflow_v5(dp)
448: const CNF_DATA_V5 *dp;
449: {
450: FILE *fp;
451:
452: if (!dump_file || (fp = fopen(dump_file, "a")) == 0)
453: return;
454:
455: fprintf(fp, "\nNetflow: V5\n");
456: fprintf(fp, "SrcAddr: %s\n", intoa(dp->src_addr));
457: fprintf(fp, "DstAddr: %s\n", intoa(dp->dst_addr));
458: fprintf(fp, "NextHop: %s\n", intoa(dp->nexthop));
459: fprintf(fp, "InputIf: %d\n", (int)ntohs(dp->ifin));
460: fprintf(fp, "OutputIf: %d\n", (int)ntohs(dp->ifout));
461: fprintf(fp, "Packets: %u\n", (u_int32_t)ntohl(dp->dpkts));
462: fprintf(fp, "Octets: %u\n", (u_int32_t)ntohl(dp->doctets));
463: fprintf(fp, "First: %u\n", (u_int32_t)ntohl(dp->firsttime));
464: fprintf(fp, "Last: %u\n", (u_int32_t)ntohl(dp->lasttime));
465: if (dp->proto == IPPROTO_TCP) {
466: fprintf(fp, "SrcPort: %s\n", tcpport_string(ntohs(dp->src_port)));
467: fprintf(fp, "DstPort: %s\n", tcpport_string(ntohs(dp->dst_port)));
468: } else if (dp->proto == IPPROTO_UDP) {
469: fprintf(fp, "SrcPort: %s\n", udpport_string(ntohs(dp->src_port)));
470: fprintf(fp, "DstPort: %s\n", udpport_string(ntohs(dp->dst_port)));
471: } else {
472: fprintf(fp, "SrcPort: %d\n", (int)ntohs(dp->src_port));
473: fprintf(fp, "DstPort: %d\n", (int)ntohs(dp->dst_port));
474: }
475: fprint_tcpflags(fp, dp->flags);
476: fprintf(fp, "Protocol: %s\n", ipproto_string(dp->proto));
477: fprint_tos(fp, dp->tos);
478:
479: fprintf(fp, "SrcASN: %d\n", (int)ntohs(dp->src_as));
480: fprintf(fp, "DstASN: %d\n", (int)ntohs(dp->dst_as));
481: fprintf(fp, "SrcMask: %d\n", (int)dp->src_mask);
482: fprintf(fp, "DstMask: %d\n", (int)dp->dst_mask);
483:
484: (void)fclose(fp);
485: }
486:
487: static void
488: dump_netflow_v7(dp)
489: const CNF_DATA_V7 *dp;
490: {
491: FILE *fp;
492:
493: if (!dump_file || (fp = fopen(dump_file, "a")) == 0)
494: return;
495:
496: fprintf(fp, "\nNetflow: V7\n");
497: fprintf(fp, "SrcAddr: %s\n", intoa(dp->src_addr));
498: fprintf(fp, "DstAddr: %s\n", intoa(dp->dst_addr));
499: fprintf(fp, "NextHop: %s\n", intoa(dp->nexthop));
500: fprintf(fp, "InputIf: %d\n", (int)ntohs(dp->ifin));
501: fprintf(fp, "OutputIf: %d\n", (int)ntohs(dp->ifout));
502: fprintf(fp, "Packets: %u\n", (u_int32_t)ntohl(dp->dpkts));
503: fprintf(fp, "Octets: %u\n", (u_int32_t)ntohl(dp->doctets));
504: fprintf(fp, "First: %u\n", (u_int32_t)ntohl(dp->firsttime));
505: fprintf(fp, "Last: %u\n", (u_int32_t)ntohl(dp->lasttime));
506: if (dp->proto == IPPROTO_TCP) {
507: fprintf(fp, "SrcPort: %s\n", tcpport_string(ntohs(dp->src_port)));
508: fprintf(fp, "DstPort: %s\n", tcpport_string(ntohs(dp->dst_port)));
509: } else if (dp->proto == IPPROTO_UDP) {
510: fprintf(fp, "SrcPort: %s\n", udpport_string(ntohs(dp->src_port)));
511: fprintf(fp, "DstPort: %s\n", udpport_string(ntohs(dp->dst_port)));
512: } else {
513: fprintf(fp, "SrcPort: %d\n", (int)ntohs(dp->src_port));
514: fprintf(fp, "DstPort: %d\n", (int)ntohs(dp->dst_port));
515: }
516: fprint_tcpflags(fp, dp->flags);
517: fprintf(fp, "Protocol: %s\n", ipproto_string(dp->proto));
518: fprint_tos(fp, dp->tos);
519:
520: fprintf(fp, "SrcASN: %d\n", (int)ntohl(dp->src_as));
521: fprintf(fp, "DstASN: %d\n", (int)ntohl(dp->dst_as));
522: fprintf(fp, "SrcMask: %d\n", (int)dp->src_mask);
523: fprintf(fp, "DstMask: %d\n", (int)dp->dst_mask);
524:
525: fprintf(fp, "RouterSc: %s\n", intoa(dp->router_sc));
526:
527: (void)fclose(fp);
528: }
529:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>