/* $Id: aguri_pcap.c,v 1.5 2003/03/12 14:09:32 kjc Exp kjc $ */ /* * Copyright (C) 2001-2003 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aguri.h" #include "aguri_tree.h" #include "aguri_ip.h" #include "aguri_pcap.h" #include "read_pcap.h" u_int64_t caplen_total = 0; int caplen_max = 0; int interval; int reading_pcap = 0; int summary_pending = 0; static pcap_t *pd; static int packet_length; /* length of current packet */ static char errbuf[PCAP_ERRBUF_SIZE]; int open_pcapfile(char *file) { int fd; pd = pcap_open_offline(file, errbuf); if (pd == NULL) err(1, "%s", errbuf); net_reader = lookup_printer(pcap_datalink(pd)); fd = fileno(pcap_file(pd)); return (fd); } int open_pcapif(char *interface, char *filter_cmd) { int snaplen, fd; char *device; struct bpf_program bprog; if (interface == NULL) { device = pcap_lookupdev(errbuf); if (device == NULL) errx(1, "%s", errbuf); } else device = interface; fprintf(stderr, "packet filter: using device %s\n", device); snaplen = DEFAULT_SNAPLEN; pd = pcap_open_live(device, snaplen, 1, 0, errbuf); if (pd == NULL) errx(1, "%s", errbuf); if (pcap_compile(pd, &bprog, filter_cmd, 0, 0) < 0) err(1, "pcap_compile: %s", pcap_geterr(pd)); else if (pcap_setfilter(pd, &bprog) < 0) err(1, "pcap_setfilter: %s", pcap_geterr(pd)); /* * Let user own process after socket has been opened. */ setuid(getuid()); net_reader = lookup_printer(pcap_datalink(pd)); fd = pcap_fileno(pd); #if defined(BSD) && defined(BPF_MAXBUFSIZE) { /* check the buffer size */ u_int bufsize; if (ioctl(fd, BIOCGBLEN, (caddr_t)&bufsize) < 0) perror("BIOCGBLEN"); else fprintf(stderr, "bpf buffer size is %d\n", bufsize); } #endif /* BSD */ return (fd); } void close_pcap(int fd) { pcap_close(pd); pd = NULL; } void print_pcapstat(FILE *fp) { struct pcap_stat stat; static struct pcap_stat last_stat; /* can't print the summary if reading from a savefile */ if (pd != NULL && pcap_file(pd) == NULL) { if (pcap_stats(pd, &stat) < 0) fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd)); else { fprintf(fp, "%%%u packets received by filter\n", stat.ps_recv - last_stat.ps_recv); fprintf(fp, "%%%u packets dropped by kernel\n", stat.ps_drop - last_stat.ps_drop); last_stat = stat; } } } int read_pcap(int fd) { int rval; reading_pcap = 1; rval = pcap_dispatch(pd, 1, dump_reader, 0); reading_pcap = 0; if (summary_pending) { summary_pending = 0; if (wfile != NULL && freopen(wfile, "a", stdout) == NULL) err(1, "can't freopen %s", wfile); } if (rval < 0) (void)fprintf(stderr, "pcap_dispatch:%s\n", pcap_geterr(pd)); return (rval); } int do_pkthdr(const struct timeval *ts, u_int caplen, u_int len) { if (caplen > caplen_max) caplen_max = caplen; caplen_total += caplen; if (start_time.tv_sec == 0) { /* * first packet. initialize the start time. * if interval is specified, skip to the next boundary. */ if (interval != 0 && ts->tv_sec % interval != 0) return (0); start_time = *ts; } end_time = *ts; /* keep the timestamp of the last packet */ if (interval != 0 && end_time.tv_sec - start_time.tv_sec >= interval) { print_summary(); if (addr_src != NULL) tree_resetcount(addr_src); if (addr6_src != NULL) tree_resetcount(addr6_src); if (addr_dst != NULL) tree_resetcount(addr_dst); if (addr6_dst != NULL) tree_resetcount(addr6_dst); if (proto_src != NULL) tree_resetcount(proto_src); if (proto_dst != NULL) tree_resetcount(proto_dst); start_time = *ts; } packet_length = len; return (1); } int do_ip(const struct ip *ip) { if (addr_src != NULL) leaf_addcount(addr_src, &ip->ip_src, packet_length); if (addr_dst != NULL) leaf_addcount(addr_dst, &ip->ip_dst, packet_length); return (1); } #ifdef INET6 int do_ip6(const struct ip6_hdr *ip6) { if (addr6_src != NULL) leaf_addcount(addr6_src, &ip6->ip6_src, packet_length); if (addr6_dst != NULL) leaf_addcount(addr6_dst, &ip6->ip6_dst, packet_length); return (1); } #endif int do_ipproto(int proto, const u_char *bp, int length) { struct proto pdata; u_short sport, dport; if ((xflags & CHECK_IPV4) == 0) return (0); pdata.p_ipver = 4; pdata.p_proto = proto; sport = dport = 0; switch (proto) { case IPPROTO_TCP: if (bp + 4 <= snapend) { /* long enough to get ports */ struct tcphdr *tcp = (struct tcphdr *)bp; sport = tcp->th_sport; dport = tcp->th_dport; } break; case IPPROTO_UDP: if (bp + 4 <= snapend) { /* long enough to get ports */ struct udphdr *udp = (struct udphdr *)bp; sport = udp->uh_sport; dport = udp->uh_dport; } break; case IPPROTO_ICMP: /* take icmp_type and icmp_code as port */ if (bp + 2 <= snapend) sport = dport = *(u_short *)bp; break; } if (proto_src != NULL) { pdata.p_port = sport; leaf_addcount(proto_src, &pdata, packet_length); } if (proto_dst != NULL) { pdata.p_port = dport; leaf_addcount(proto_dst, &pdata, packet_length); } return (1); } #ifdef INET6 int do_ip6nexthdr(int proto, const u_char *bp, int length) { struct proto pdata; u_short sport, dport; if ((xflags & CHECK_IPV6) == 0) return (0); pdata.p_ipver = 6; pdata.p_proto = proto; sport = dport = 0; switch (proto) { case IPPROTO_TCP: if (bp + 4 <= snapend) { /* long enough to get ports */ struct tcphdr *tcp = (struct tcphdr *)bp; sport = tcp->th_sport; dport = tcp->th_dport; } break; case IPPROTO_UDP: if (bp + 4 <= snapend) { /* long enough to get ports */ struct udphdr *udp = (struct udphdr *)bp; sport = udp->uh_sport; dport = udp->uh_dport; } break; case IPPROTO_ICMPV6: /* take icmp_type and icmp_code as port */ if (bp + 2 <= snapend) sport = dport = *(u_short *)bp; break; } if (proto_src != NULL) { pdata.p_port = sport; leaf_addcount(proto_src, &pdata, packet_length); } if (proto_dst != NULL) { pdata.p_port = dport; leaf_addcount(proto_dst, &pdata, packet_length); } return (1); } #endif /* INET6 */