void fg_pcap_init() { /* initalize *alldevs for later use */ #ifdef DEBUG pcap_if_t *d; char devdes[200]; #endif /* DEBUG */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { logging_log(LOG_WARNING,"Error in pcap_findalldevs: %s\n", errbuf); return; } #ifdef DEBUG for (d = alldevs; d; d = d->next) { pcap_addr_t *a; snprintf(devdes, sizeof(devdes), "%s: ", d->name); for (a = d->addresses; a; a = a->next) { char addr[100]; if (!a->addr) continue; snprintf(addr, sizeof(addr), "a=%s", fg_nameinfo(a->addr, sizeof(struct sockaddr))); strncat(devdes, addr, sizeof(devdes) - strlen(devdes) - 1); if (a->next) strncat(devdes, ", ", sizeof(devdes) - strlen(devdes) - 1); } DEBUG_MSG(LOG_ERR, "pcap: found pcapable device (%s)", devdes); } #endif /* DEBUG*/ pthread_mutex_init(&pcap_mutex, NULL); #ifndef __DARWIN__ pthread_barrier_init(&pcap_barrier, NULL, 2); #endif /* __DARWIN__ */ return; }
int get_imtu(int fd) /* returns interface mtu */ { struct sockaddr_storage sa; socklen_t sl = sizeof(sa); struct ifreq ifreqs[20]; struct ifconf ifconf; int nifaces, i, mtu = 0; memset(&ifconf,0,sizeof(ifconf)); ifconf.ifc_buf = (char*)(ifreqs); ifconf.ifc_len = sizeof(ifreqs); if (getsockname(fd, (struct sockaddr *)&sa, &sl) < 0) return 0; if (ioctl(fd, SIOCGIFCONF, &ifconf) < 0) return 0; nifaces = ifconf.ifc_len/sizeof(struct ifreq); for(i = 0; i < nifaces; i++) { if (sockaddr_compare((struct sockaddr *)&ifreqs[i].ifr_addr, (struct sockaddr *)&sa)) break; } if (ioctl(fd, SIOCGIFMTU, &ifreqs[i]) < 0) return 0; DEBUG_MSG(LOG_NOTICE, "interface %s (%s) has mtu %d", ifreqs[i].ifr_name, fg_nameinfo((struct sockaddr *)&ifreqs[i].ifr_addr, sizeof(struct sockaddr)), ifreqs[i].ifr_mtu); mtu = ifreqs[i].ifr_mtu; if (mtu > 0) return mtu; else return 0; }
static void* fg_pcap_work(void* arg) { /* note: all the wierd casts in this function are completely useless, * execpt they cirumvent strange compiler warnings because of libpcap * typedef woo's */ #ifdef DEBUG struct pcap_stat p_stats; #endif /* DEBUG */ int rc; struct _flow * flow; flow = (struct _flow *) arg; pcap_if_t *d; struct sockaddr_storage sa; socklen_t sl = sizeof(sa); char found = 0; uint32_t net = 0; uint32_t mask = 0; char dump_filename[500]; char hostname[100]; struct bpf_program pcap_program; struct timespec now; char buf[60]; DEBUG_MSG(LOG_DEBUG, "fg_pcap_thread() called for flow %d", flow->id); /* make sure all resources are released when finished */ pthread_detach(pthread_self()); pthread_cleanup_push(fg_pcap_cleanup, (void*) flow); if (getsockname(flow->fd, (struct sockaddr *)&sa, &sl) == -1) { logging_log(LOG_WARNING, "getsockname() failed. Eliding " "packet capture for flow."); goto remove; } /* find appropriate (used for test) interface to dump */ for (d = alldevs; d; d = d->next) { pcap_addr_t *a; for (a = d->addresses; a; a = a->next) { if (!a->addr) continue; if (sockaddr_compare(a->addr, (struct sockaddr *)&sa)) { DEBUG_MSG(LOG_NOTICE, "pcap: data connection " "inbound from %s (%s)", d->name, fg_nameinfo(a->addr, sizeof(struct sockaddr))); found = 1; break; } } if (found) break; } if (!found) { logging_log(LOG_WARNING, "Failed to determine interface " "for data connection. No pcap support."); goto remove; } /* Make sure errbuf contains zero-length string in order to enable * pcap_open_live to report warnings. */ errbuf[0] = '\0'; flow->pcap_handle = (struct pcap_t *)pcap_open_live(d->name, PCAP_SNAPLEN, PCAP_PROMISC, 0, /* no read timeout */ errbuf); if (!flow->pcap_handle) { logging_log(LOG_WARNING, "Failed to init pcap on device %s:" " %s", d->name, errbuf); goto remove; } if (pcap_lookupnet(d->name, &net, &mask, errbuf) < 0) { logging_log(LOG_WARNING, "pcap: netmask lookup failed: %s", errbuf); goto remove; } /* We rely on a non-blocking dispatch loop */ if (pcap_setnonblock((pcap_t *)flow->pcap_handle, 1 /* non-blocking */, errbuf) < 0) { logging_log(LOG_WARNING, "pcap: failed to set non-blocking: " "%s", errbuf); goto remove; } /* compile filter */ if (pcap_compile((pcap_t *)flow->pcap_handle, &pcap_program, PCAP_FILTER, 1, mask) < 0) { logging_log(LOG_WARNING, "pcap: failed compiling filter " "'%s': %s", PCAP_FILTER, pcap_geterr((pcap_t *)flow->pcap_handle)); goto remove; } /* attach filter to interface */ if (pcap_setfilter((pcap_t *)flow->pcap_handle, &pcap_program) < 0) { logging_log(LOG_WARNING, "pcap: failed to set filter: " "%s", pcap_geterr((pcap_t *)flow->pcap_handle)); goto remove; } /* generate a nice filename */ dump_filename[0] = '\0'; /* dir and prefix */ if (dump_dir) strcat(dump_filename, dump_dir); if (dump_prefix) strcat(dump_filename, dump_prefix); /* timestamp */ gettime(&now); strftime(buf, sizeof(buf), "%Y-%m-%d-%H:%M:%S", localtime(&now.tv_sec)); strcat(dump_filename, buf); /* hostname */ hostname[0]= '\0'; if (!gethostname(hostname, 59)) { strcat(dump_filename, "-"); strcat(dump_filename, hostname); } /* interface */ strcat(dump_filename, "-"); strcat(dump_filename, d->name); /* suffix */ strcat(dump_filename, ".pcap"); DEBUG_MSG(LOG_NOTICE, "dumping to \"%s\"", dump_filename); flow->pcap_dumper = (struct pcap_dumper_t *)pcap_dump_open( (pcap_t *)flow->pcap_handle, dump_filename); if (!flow->pcap_dumper) { logging_log(LOG_WARNING, "pcap: failed to open dump file " "writing: %s", pcap_geterr((pcap_t *)flow->pcap_handle)); goto remove; } /* barrier: dump is ready */ #ifndef __DARWIN__ pthread_barrier_wait(&pcap_barrier); #endif /* __DARWIN__ */ for (;;) { rc = pcap_dispatch((pcap_t *)flow->pcap_handle, -1, &pcap_dump, (u_char *)flow->pcap_dumper); if (rc < 0) { logging_log(LOG_WARNING, "pcap_dispatch() failed. " "Packet dumping stopped for flow %d.", flow->id); /* cleanup automatically called */ pthread_exit(0); } #ifdef DEBUG pcap_stats((pcap_t *)flow->pcap_handle, &p_stats); #endif /* DEBUG */ DEBUG_MSG(LOG_NOTICE, "pcap: finished dumping %u packets for " "flow %d", rc, flow->id); DEBUG_MSG(LOG_NOTICE, "pcap: %d packets received by filter for " "flow %d", p_stats.ps_recv, flow->id); DEBUG_MSG(LOG_NOTICE, "pcap: %d packets dropped by kernel for " "flow %d", p_stats.ps_drop, flow->id); if (rc == 0) /* if no packets are received try * if we should cancel */ pthread_testcancel(); } pthread_cleanup_pop(1); remove: #ifndef __DARWIN__ pthread_barrier_wait(&pcap_barrier); #endif /* __DARWIN__ */ return 0; }