/*-
* 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/ipex.c,v 1.51 2005/05/18 17:32:38 modulus Exp $";
#endif
#include <ipex_includes.h>
#define READ_TIMEOUT 1000
#define NO_PRINT 0x7f
static char **protocols;
static char **tcp_ports;
static char **udp_ports;
/*
* lookup table, the function pointer in delegate will initialize by
* retrieving the * ip_p section of the IP header and using it to
* cross reference it's arbitrary handler in this table.
*/
static struct proto_printers {
u_char pp_proto; /* ip protocol */
int pp_hlen; /* required header length */
int (*pp_printer)(u_char *, struct pcap_pkthdr *, u_char *);
} p_funcs[] = {
{ IPPROTO_TCP, 24, print_tcp },
{ IPPROTO_ICMP, 4, print_icmp },
{ IPPROTO_UDP, 8, print_udp },
{ NO_PRINT, 0, generic_print },
{ 0, 0, NULL }
};
pcap_t *pd = NULL;
pcap_dumper_t *pdmper;
Heap *conqueue;
static int
offline(void)
{
char ebuf[32];
pd = pcap_open_offline(opts.rflag, ebuf);
if (pd == NULL)
errx(EX_DATAERR, "fatal: pcap_open_offline: failed to "
"init pcap: %s", ebuf);
}
int
main(int argc, char *argv [])
{
char ebuf[PCAP_ERRBUF_SIZE + 32];
int fg = 1, ch, cnt, snaplen = 65535;
glob_t g;
FILE *cmdfp;
char *cmdbuf, *fname, *rem;
u_char *pargs;
static struct in_addr localnet, netmask;
struct bpf_program bpfcode;
struct pcap_stat pstat;
struct dump_info info;
pcap_handler printer;
struct stat sb;
cmdbuf = NULL;
memset(&opts, 0, sizeof(opts));
opts.thiszone = gmt2local(0);
opts.qflag = 1;
while ((ch = getopt(argc, argv, "a:c:df:e:hi:lnpqr:t:u:vw:xB:C:DE:F:HLNOP:\
RST:X")) != -1)
switch(ch) {
case 'a':
if (strncasecmp(optarg, "all", 4) == 0) {
g.gl_offs=1;
glob("*.dmp*", 0, NULL, &g);
for(cnt = 0; cnt < g.gl_pathc; cnt++) {
fname = chomp(g.gl_pathv[cnt]);
disassemble_fname(fname);
}
} else {
fname = chomp(optarg);
disassemble_fname(fname);
}
exit(EX_OK);
break; /* NOT REACHED */
case 'c':
opts.cflag = strtoul(optarg, &rem, 0);
if (*rem || rem == optarg || opts.cflag > LONG_MAX ||
!opts.cflag)
errx(EX_USAGE, "invalid packet count" \
" specification.");
break;
case 'd':
opts.dflag++;
break;
case 'e':
opts.eflag = optarg;
readtimespec(opts.eflag);
break;
case 'f':
opts.fflag = optarg;
if (stat(opts.fflag, &sb) < 0)
err(1, "stat failed");
cmdbuf = malloc(sb.st_size);
if (cmdbuf == NULL)
err(1, "malloc failed");
if ((cmdfp = fopen(opts.fflag, "r")) == NULL)
errx(EX_NOINPUT, "unable to open rules file.");
logic_load(cmdbuf, cmdfp);
fclose(cmdfp);
break;
case 'h':
usage(NULL);
exit(EX_USAGE);
break;
/* NOT REACHED */
case 'i':
opts.iflag = optarg;
break;
case 'l':
setvbuf(stdout, NULL, _IOLBF, 0);
break;
case 'n':
opts.nflag++;
break;
case 'p':
opts.pflag++;
break;
case 'q':
opts.qflag = 0;
break;
case 'r':
opts.rflag = optarg;
break;
case 't':
opts.tflag = strtoul(optarg, &rem, 0);
if (*rem || rem == optarg || opts.uflag > LONG_MAX ||
!opts.tflag)
errx(EX_USAGE, "invalid timeout specification.");
break;
case 'u':
opts.uflag = strtoul(optarg, &rem, 0);
if (*rem || rem == optarg || opts.uflag > LONG_MAX ||
!opts.uflag)
errx(EX_USAGE, "invalid UID specification.");
break;
case 'v':
printf("%s\n", _VERSION);
exit(0);
break;
case 'w':
opts.wflag = optarg;
break;
case 'x':
opts.xflag++;
break;
case 'B':
opts.Bflag = optarg;
ln_pattern(opts.Bflag);
break;
case 'C':
opts.Cflag = parseCflag(optarg);
if (!opts.Cflag)
errx(1, "size specification out of bounds");
break;
case 'D':
opts.Dflag++;
break;
case 'E':
opts.Eflag = optarg;
break;
case 'H':
/* If we are just processing packet headers then
* there is no point is capturing the entire frame
* off the wire. Set the snaplen to 100.
*/
snaplen = 100;
opts.Hflag++;
break;
case 'L':
opts.Lflag++;
break;
case 'O':
opts.Oflag = 1;
break;
case 'R':
opts.Rflag++;
break;
case 'P':
#if !defined __POWERPC__ && !defined linux
opts.Pflag = optarg;
scan_descriptor_tables(opts.Pflag);
cmdbuf = (char *)compile_logic_list();
#else
errx(EX_USAGE, "-P not yet supported on this system.");
#endif
break;
case 'T':
opts.Tflag = atoi(optarg);
break;
default:
usage(NULL);
exit(EX_USAGE);
}
argv += optind;
argc -= optind;
if (!opts.iflag && !opts.rflag)
if (!(opts.iflag = pcap_lookupdev(ebuf)))
errx(EX_USAGE, "fatal: pcap_lookupdev: %s", ebuf);
handle_signals();
if (!opts.pflag)
init_tabs();
if (!opts.fflag && !opts.Pflag) {
cmdbuf = retrive_pcap_expr(argv);
if (cmdbuf == NULL)
cmdbuf = " ";
}
if (opts.rflag != NULL)
offline();
else {
pd = pcap_open_live(opts.iflag, snaplen, opts.qflag,
READ_TIMEOUT, ebuf);
if (pd == NULL)
errx(EX_DATAERR, "fatal: pcap_open_live: %s", ebuf);
}
#if (!defined(linux))
if (opts.Rflag && !opts.wflag)
if (ioctl(pd->fd, BIOCIMMEDIATE, &fg) < 0)
errx(EX_OSERR, "fatal: ioctl(BIOCIMMEDIATE) failed.");
#endif
if (opts.wflag) {
pdmper = pcap_dump_open(pd, opts.wflag);
if (pdmper == NULL)
errx(EX_NOINPUT, "fatal: pcap_dump_open: %s",
pcap_geterr(pd));
info.WFileName = opts.wflag;
info.pd = pd;
info.p = pdmper;
}
fprintf(stderr, "ipex: reading packets from %s\n",
opts.rflag ? opts.rflag : opts.iflag);
if (!opts.rflag) {
if (pcap_lookupnet(opts.iflag, &localnet.s_addr,
&netmask.s_addr, ebuf) < 0) {
memset(&localnet, 0, sizeof(localnet));
memset(&netmask, 0, sizeof(netmask));
fprintf(stderr,"warning: pcap_lookupnet failed\n");
}
}
if (pcap_compile(pd, &bpfcode, cmdbuf, opts.Oflag,
netmask.s_addr) < 0)
errx(EX_DATAERR, "fatal: pcap_compile: %s", pcap_geterr(pd));
if (pcap_setfilter(pd, &bpfcode) < 0)
errx(EX_DATAERR, "fatal: pcap_setfilter() failed");
if ((opts.loffset = datalink_lookup_offset(pd)) == -1)
errx(EX_UNAVAILABLE, "fatal: unsupported interface type");
printer = (pcap_handler)delegate;
pargs = (caddr_t)&info;
pcap_loop(pd, opts.cflag, printer, pargs);
if (!opts.rflag) {
pcap_stats(pd, &pstat);
fprintf(stderr, "\nsession statistics: %d packets"
"received, %d dropped\n", pstat.ps_recv, pstat.ps_drop);
}
pcap_close(pd);
return (0);
}
void
cleanup(void)
{
struct pcap_stat pstat;
pcap_stats(pd, &pstat);
fprintf(stderr, "\ninterrupted: session stats: %d packets received, "
"%d dropped\n", pstat.ps_recv, pstat.ps_drop);
free(protocols);
free(tcp_ports);
free(udp_ports);
flush_ns_cache();
if (opts.Tflag)
heap_destory(conqueue);
pcap_close(pd);
exit(0);
}
struct proto_printers *
get_proto_printer(u_char proto, int caplen)
{
struct proto_printers *p;
for (p = p_funcs; p->pp_printer; p++)
if (proto == p->pp_proto) {
/*
* extra check here to make sure we have enough
* data from the wire to align the proper protocol
* header later.
*/
if (caplen >= p->pp_hlen)
return (p);
else
break;
}
return (NULL);
}
int
datalink_lookup_offset(pcap_t *p)
{
switch(pcap_datalink(p)) {
case DLT_EN10MB:
case DLT_IEEE802:
return(ETHHDR_SIZE);
case DLT_FDDI:
return(FDDIHDR_SIZE);
case DLT_SLIP:
return(SLIPHDR_SIZE);
case DLT_PPP:
return(PPPHDR_SIZE);
case DLT_RAW:
return(RAWHDR_SIZE);
#ifdef HAVE_NET_IF_PFLOG_H
case DLT_PFLOG:
return(PFLOG_HDRLEN);
#endif
case DLT_NULL:
return(LOOPHDR_SIZE);
default:
break;
}
return(-1); /* unknown datalink layer type */
}
pcap_handler
delegate(u_char *pargs, struct pcap_pkthdr *h, u_char *p)
{
struct ip *ip;
struct proto_printers *pp, pr;
int match;
char block[65535];
struct offset off;
if (opts.Eflag) {
memset(&off, 0, sizeof(off));
memcpy(&block[0], p, h->len);
rettext(&block[0], h->len);
block[h->len] = 0;
if (!grep(opts.Eflag, &block[0], &off))
return (NULL);
}
if (opts.eflag) {
match = ((h->ts.tv_sec >= dsp->lower) &&
(h->ts.tv_sec <= dsp->upper));
if (!match)
return (NULL);
}
if (opts.Bflag != NULL)
if (!detectpattern(p, h->len))
return (NULL);
if (opts.Tflag) {
handle_sessions(h, p);
/* XXX should we be printing the sessions? */
return (NULL);
}
if (opts.tflag) {
statetrack(pargs, h, p);
return (NULL);
}
if (opts.wflag) {
dump_and_trunc(pargs, h, p);
return (NULL);
}
ip = (struct ip *)(p + opts.loffset);
pp = get_proto_printer(ip->ip_p, h->caplen);
if (pp == NULL) {
pp = ≺
pp->pp_printer = generic_print;
}
pp->pp_printer(NULL, h, p);
if (opts.Hflag)
return (NULL);
if (opts.xflag)
ascii_print_with_offset(p, h->len, 0, 1);
else
text_dump(p, h->len, &off);
return (NULL);
}
int
usage(char *base)
{
fprintf(stderr,
"usage: ipex [-hvnqbHxTLGdO] [-f config] [-r pattern] [-o outfile]\n"
" [-c count] [-i interface] [-u uid] [-P op=arg]\n"
" [-t time] [-w file] [-F file] [expression] [-B file]\n");
return (1);
}
/* Service lookup routines were snagged from IP Filter's ipmon. */
void
init_tabs(void)
{
struct protoent *p;
struct servent *s;
char *name, **tab;
int port;
if (protocols != NULL) {
free(protocols);
protocols = NULL;
}
protocols = memalloc(256 * sizeof(*protocols));
memset(protocols, 0, 256 * sizeof(*protocols));
setprotoent(1);
while ((p = getprotoent()) != NULL)
if (p->p_proto >= 0 && p->p_proto <= 255 && p->p_name != NULL)
protocols[p->p_proto] = strdup(p->p_name);
endprotoent();
if (udp_ports != NULL) {
free(udp_ports);
udp_ports = NULL;
}
udp_ports = memalloc(65536 * sizeof(*udp_ports));
if (udp_ports != NULL)
memset(udp_ports, 0, 65536 * sizeof(*udp_ports));
if (tcp_ports != NULL) {
free(tcp_ports);
tcp_ports = NULL;
}
tcp_ports = memalloc(65536 * sizeof(*tcp_ports));
if (tcp_ports != NULL)
memset(tcp_ports, 0, 65536 * sizeof(*tcp_ports));
setservent(1);
while ((s = getservent()) != NULL) {
if (s->s_proto == NULL)
continue;
else if (!strcmp(s->s_proto, "tcp")) {
port = ntohs(s->s_port);
name = s->s_name;
tab = tcp_ports;
} else if (!strcmp(s->s_proto, "udp")) {
port = ntohs(s->s_port);
name = s->s_name;
tab = udp_ports;
} else
continue;
if ((port < 0 || port > 65535) || (name == NULL))
continue;
tab[port] = strdup(name);
}
return;
}
char *
getproto(u_int p)
{
static char pnum[4];
char *s;
p &= 0xff;
s = protocols ? protocols[p] : NULL;
if (s == NULL) {
sprintf(pnum, "%u", p);
s = pnum;
}
return (s);
}
char *
portname(int res, char *proto, u_int port)
{
static char pname[8];
char *s;
port = ntohs(port);
port &= 0xffff;
if (opts.pflag) {
sprintf(pname, "%u", port);
return (&pname[0]);
}
s = NULL;
if (!strcmp(proto, "tcp"))
s = tcp_ports[port];
else if (!strcmp(proto, "udp"))
s = udp_ports[port];
if (s == NULL) {
sprintf(pname, "%u", port);
s = pname;
}
return (s);
}
syntax highlighted by Code2HTML, v. 0.9.1