/*- * Copyright (c) 2001-2005 Christian S.J. Peron * 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. */ #ifndef lint static const char rcsid[] = "@(#) $Header: /usr/cvs/ipex/proc_kvm.c,v 1.4 2005/02/25 08:46:11 modulus Exp $"; #endif #include "ipex_includes.h" #if !defined __POWERPC__ && !defined linux int count = 0; /* * should we run acorss multiple socket * sets per process in /dev/mem. We * will queue them in this list, so * that we might generate a functional * pcap logic string for the capturing of * the packets. */ void queue_logic(char *pcap_logic) { struct connections *p; if ((p = calloc(1, sizeof(*p))) == 0) { printf("fatal: calloc: unable to allocate memory\n"); exit(EXIT_FAILURE); } p->pcap_logic = pcap_logic; assert(p->pcap_logic); SLIST_INSERT_HEAD(&list, p, next); count++; return; } /* * after we are done, no need to have the memory * allocated for the process. Free the list and * carry on. */ void flush_logic(void) { struct connections *p; while (!SLIST_EMPTY(&list)) { p = SLIST_FIRST(&list); assert(p); SLIST_REMOVE_HEAD(&list, next); free(p); } return; } /* * now that we have our list built will all the proper * connections, we will setup a function to take * the list and generate the ruleset that pcap * will use to capture the packets. */ char * compile_logic_list(void) { static char logic[1024]; int off = 0; struct connections *p; if (count == 0) { printf("fatal: no PF_INET sockets located in process.\n"); exit(1); } if ((p = calloc(1, sizeof(*p))) == 0) { printf("fatal: calloc: unable to allocate memory\n"); exit(EXIT_FAILURE); } memset(&logic, 0, sizeof(logic)); SLIST_FOREACH(p, &list, next) { assert(p->pcap_logic); strncat(logic, p->pcap_logic, strlen(p->pcap_logic)); off++; if (off < count) { strncat(logic, " or ", 4); } } flush_logic(); /* cleanup memory */ return(logic); } /* * if autoconf discovered that struct kproc_info had * a ki_addr member, we are dealing with the -CURRENT * branch of BSD, so we will adjust the process status, * process pointer and process open files strucuts as * required */ #if (!defined(HAVE_KI_ADDR)) /* NOT FREEBSD 5.0 -CURRENT? */ #define P_ADDR kp_eproc.e_paddr #define P_FD kp_proc.p_fd #define P_STAT kp_proc.p_stat #endif /* ! HAVE_KI_ADDR ! */ #if (defined(HAVE_KI_ADDR)) /* FREEBSD 5.0 -CURRENT */ #define P_ADDR ki_paddr #define P_FD ki_fd #define P_STAT ki_stat #endif /* HAVE_KI_ADDR */ /* * global kernel descriptor */ kvm_t *kd; /* kernel descriptor */ void scan_descriptor_tables(char *buf) { struct file *Cfp; struct kinfo_proc *p, *plast; struct filedesc fd; static struct file **ofb = NULL; static int ofbb = 0; int i, nf; int cnt = 0; size_t nb; struct core *uap; if ((uap = proc_args(buf)) == NULL) { printf("fatal: invalid arguments and/or operation for -P\n"); exit(1); } if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL) { printf("fatal: mem: could not open core\n"); exit(1); } if ((p = kvm_getprocs(kd, opts.op, opts.arg, &cnt)) == NULL) { printf("fatal: kvm_getprocs: could not retrieve process pointers\n"); exit(1); } free(uap); for (plast = &p[cnt]; p < plast; ++p) { if (p->P_STAT == SZOMB) { continue; } if (!p->P_FD || kread((kvm_t *)p->P_FD, (char *)&fd, sizeof(fd))) { printf("fatal: kvm_read: could not locate process descriptors\n"); exit(1); } if (!fd.fd_ofiles || (nf = fd.fd_nfiles) <= 0) { printf("fatal: no descriptors located in process\n"); exit(1); } nb = (size_t)(sizeof(struct file *) * nf); if (nb > ofbb) { if (!ofb) ofb = (struct file **)memalloc(nb); else ofb = (struct file **)memrealloc((void *)ofb, nb); ofbb = nb; } kread((kvm_t *)fd.fd_ofiles, (char *)ofb, nb); /* * process descriptor tables so we can * grab the PF_INET sockets from them and * generate a pcap logic string for the process's. */ for (i = 0; i < nf; i++) { if (ofb[i]) { Cfp = ofb[i]; process_descriptors((void *)Cfp); } } } return; } /* * all we want are the descriptors which have x.f_type * DTYPE_SOCKET, we are not interested in any other * descriptor types for the purpose of the function. * If we find a descriptor which is DTYPE_SOCKET lets * process it. */ void process_descriptors(kvm_t *fp) { struct file f; if (kread((kvm_t *)fp, (char *)&f, sizeof(f))) { printf("fatal: cant read file structure\n"); exit(1); } if (f.f_type == DTYPE_SOCKET) { process_socket(f.f_data); } return; } int kread(kvm_t *addr, char *buf, size_t len) { int br; br = kvm_read(kd, (u_long) addr, buf, len); return((br == len) ? 0 : 1); } /* * for each DTYPE_SOCKET descriptor, that is NOT * just a listening descriptor and has a PF_INET domain * should have some connection stats we can use * to generate a null terminated and add the connection * stats string to our pcap logic queue. */ void process_socket(void *data) { struct connections *uap; char *expr; struct inpcb inp; struct domain d; struct socket s; struct protosw p; char tmp[200]; if (!data) { (void) fprintf(stderr,"fatal: socket has no address?\n"); return; } if (kread((kvm_t *)data, (char *)&s, sizeof(s))) { (void) fprintf(stderr,"diagnostic: kread: cannot read in socket structure. skipping...\n"); return; } if (!s.so_type) { (void) fprintf(stderr,"diagnostic: socket has no type. skipping...\n"); return; } if (!s.so_proto || kread((kvm_t *)s.so_proto, (char *)&p, sizeof(p))) { (void) fprintf(stderr,"diagnostic: kread: cant read socket protocol switch. skipping...\n"); } if (!p.pr_domain || kread((kvm_t *)p.pr_domain, (char *)&d, sizeof(d))) { (void) fprintf(stderr,"diagnostic: kread: cant read domain structure. skipping...\n"); return; } if (d.dom_family == AF_INET) { if (!s.so_pcb || kread((kvm_t *)s.so_pcb, (char *)&inp, sizeof(inp))) { ; } if ((inp.inp_faddr.s_addr != INADDR_ANY) || (inp.inp_fport && inp.inp_lport)) { if ((inp.inp_fport == 0) || (inp.inp_lport == 0)) { return; } snprintf(tmp, sizeof(tmp),"(port %u and %u)", (int)ntohs(inp.inp_lport), (int)ntohs(inp.inp_fport)); if ((expr = strdup(tmp)) == NULL) { return; } SLIST_FOREACH(uap, &list, next) { if (strncmp(expr, opts.pcap_logic, 20) == 0) { (void) fprintf(stderr,"diagnostic: duplicate entry. removing dupes... \n"); return; } } queue_logic(expr); } } return; } #else #define NO_PROC_KVM_DOT_H_ 1 #endif /* EOF PROC_KVM_C_ */