/*- * Copyright (c) 2001, 2003, 2004 Lev Walkin . * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * $Id: psrc.c,v 1.12 2005/07/07 05:54:53 vlm Exp $ */ #include "ipcad.h" #include "sf_lite.h" #include "opt.h" static int ifIndexes; /* Ever-increasing interface name */ packet_source_t * create_packet_source(char *ifname, int iflags, char *filter) { packet_source_t *ps; /* * Create a new interface structure. */ ps = calloc(1, sizeof *ps); if(ps == NULL) return NULL; ps->fd = -1; /* Packet source file descriptor */ /* * Fill-up the common parameters. */ strncpy( ps->ifName, ifname, sizeof(ps->ifName) ); ps->ifName[sizeof(ps->ifName) - 1] = 0; ps->iflags = iflags; ps->custom_filter = filter; ps->avg_period = 300; /* 5 minutes */ ps->bytes_lp = -1; /* Initial value */ ps->packets_lp = -1; /* Initial value */ ps->state = PST_EMBRYONIC; /* * Initialize packet source descriptors. */ if(strchr(ifname, '*')) { /* * The interface does not exist, so it might be dynamic. */ fprintf(stderr, "[DYNAMIC] "); ps->process_ptr = process_dynamic; ps->print_stats = print_stats_dynamic; ps->iface_type = IFACE_DYNAMIC; ps->iface.dynamic.already_got = genhash_new(cmpf_string, hashf_string, NULL, (void (*)(void *))destroy_packet_source); if(ps->iface.dynamic.already_got == NULL) goto failure; } else if(strncasecmp(ifname, "ulog", 5) == 0) { #ifdef PSRC_ulog u_int32_t m = 0x80000000; char *p; int i; ps->process_ptr = process_ulog; ps->print_stats = print_stats_ulog; ps->iface_type = IFACE_ULOG; ps->iface.ulog.groupmask = strtoul(ps->custom_filter, NULL, 10); ps->iface.ulog.uName = p = calloc(1, 1 + 32 * (2 + 1) + 1); if(!p) goto failure; *p++ = 'u'; /* "u"log */ for(i = 32; m; m >>= 1, i--) { assert(i >= 1); if(ps->iface.ulog.groupmask & m) { int ret = snprintf(p, 3, "%d,", i); assert(ret >= 1 && ret <= 3); p += ret; } } *(--p) = '\0'; if(p == ps->iface.ulog.uName) { ps->iface.ulog.uName = NULL; free(p); } #else /* !PSRC_ulog */ fprintf(stderr, "Linux ULOG is not supported\n"); errno = EINVAL; goto failure; #endif /* PSRC_ulog */ } else if(strncasecmp(ifname, "ipq", 4) == 0) { #ifdef PSRC_ipq ps->process_ptr = process_ipq; ps->print_stats = print_stats_ipq; ps->iface_type = IFACE_IPQ; ps->iface.ipq.peer.nl_family = AF_NETLINK; #else /* !PSRC_ipq */ fprintf(stderr, "Linux IPQ interface is not supported\n"); errno = EINVAL; goto failure; #endif /* PSRC_ipq */ } else if(strncasecmp(ifname, "divert", 7) == 0 || strncasecmp(ifname, "tee", 4) == 0) { #ifdef IPPROTO_DIVERT ps->process_ptr = process_divert; ps->print_stats = print_stats_divert; if(strncasecmp(ifname, "d", 1) == 0) ps->iface_type = IFACE_DIVERT; else ps->iface_type = IFACE_TEE; ps->iface.divert.port = atoi(ps->custom_filter); ps->bufsize = 65536 + 4096; ps->buf = malloc(ps->bufsize); if(ps->buf == NULL) { ps->bufsize = 0; goto failure; } #else /* !IPPROTO_DIVERT */ fprintf(stderr, "BSD divert(4)/tee interface is not supported\n"); errno = EINVAL; goto failure; #endif /* IPPROTO_DIVERT */ } else if(strcmp(ifname, "file") == 0) { ps->iface_type = IFACE_FILE; ps->process_ptr = process_file; ps->print_stats = print_stats_file; ps->iface.file.name = filter; ps->iface.file.dev = NULL; } else { #ifdef PSRC_bpf ps->process_ptr = process_bpf; ps->print_stats = print_stats_bpf; ps->iface_type = IFACE_BPF; #endif /* PSRC_bpf */ #ifdef PSRC_pcap ps->process_ptr = process_pcap; ps->print_stats = print_stats_pcap; ps->iface_type = IFACE_PCAP; ps->iface.pcap.dev = NULL; if(pthread_mutex_init(&ps->iface.pcap.dev_mutex, NULL) == -1) goto failure; #endif /* PSRC_pcap */ } switch(ps->iface_type) { case IFACE_DYNAMIC: break; #ifdef IPPROTO_DIVERT case IFACE_DIVERT: /* Special interface index */ ps->ifIndex = IFINDEX_DIVERT_MASK | ps->iface.divert.port; break; case IFACE_TEE: /* Special interface index */ ps->ifIndex = IFINDEX_TEE_MASK | ps->iface.divert.port; break; #endif /* IPPROTO_DIVERT */ default: ps->ifIndex = ++ifIndexes; } return ps; failure: free(ps); return NULL; } int init_packet_source(packet_source_t *ps, int retry_mode) { switch(ps->iface_type) { case IFACE_FILE: return init_packet_source_file(ps); case IFACE_DYNAMIC: return init_packet_source_dynamic(ps); case IFACE_ULOG: return init_packet_source_ulog(ps, retry_mode); case IFACE_IPQ: return init_packet_source_ipq(ps, retry_mode); case IFACE_DIVERT: case IFACE_TEE: return init_packet_source_divert(ps); default: #ifdef PSRC_bpf return init_packet_source_bpf(ps, retry_mode); #elif PSRC_pcap return init_packet_source_pcap(ps); #else #error unknown packet source #endif } } void destroy_packet_source(packet_source_t *ps) { if(ps == NULL) return; if(ps->buf) free(ps->buf); if(ps->fd != -1) close(ps->fd); switch(ps->iface_type) { case IFACE_DYNAMIC: genhash_destroy(ps->iface.dynamic.already_got); break; #ifdef PSRC_pcap case IFACE_PCAP: if(ps->iface.pcap.dev) pcap_close(ps->iface.pcap.dev); pthread_mutex_destroy(&ps->iface.pcap.dev_mutex); break; #endif default: break; } free(ps); } const char * IFNameBySource(void *psrc) { packet_source_t *ps = psrc; if(ps) { switch(ps->iface_type) { case IFACE_FILE: return ps->iface.file.name; #ifdef PSRC_ulog case IFACE_ULOG: if(ps->iface.ulog.uName) return ps->iface.ulog.uName; /* Fall through */ #endif case IFACE_DIVERT: case IFACE_TEE: return ps->custom_filter; default: return ps->ifName; } } else { return ""; } }