/*-
* 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_ */
syntax highlighted by Code2HTML, v. 0.9.1