ipfstat.c revision c0e86175870779eac2f63015968ea4f3563e40f8
/*
* Copyright (C) 1993-2001, 2003 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __FreeBSD__
# ifndef __FreeBSD_cc_version
# include <osreldate.h>
# else
# if __FreeBSD_cc_version < 430000
# include <osreldate.h>
# endif
# endif
#endif
#include <fcntl.h>
#ifdef linux
#else
# include <nlist.h>
#endif
#include <ctype.h>
# include <stddef.h>
#endif
#include "ipf.h"
#if defined(STATETOP)
# if defined(_BSDI_VERSION)
# endif
# if defined(__FreeBSD__) && \
# endif
# endif
# if defined(sun)
# else
# endif
# endif
#endif
#endif
#ifdef STATETOP
# include <ctype.h>
# include <signal.h>
defined(__sgi)
# ifdef ERR
# endif
# include <curses.h>
# else /* SOLARIS */
# include <ncurses.h>
# endif /* SOLARIS */
#endif /* STATETOP */
#include "kmem.h"
#if defined(__NetBSD__) || (__OpenBSD__)
# include <paths.h>
#endif
#if !defined(lint)
#endif
#ifdef __hpux
#endif
extern char *optarg;
extern int optind;
extern int opterr;
#define F_IN 0
#define F_OUT 1
#define F_ACIN 2
#define F_ACOUT 3
"ipacct(in)", "ipacct(out)" };
static int state_logging = -1;
int opts = 0;
int use_inet6 = 0;
int live_kernel = 1;
int state_fd = -1;
int ipf_fd = -1;
#ifdef STATETOP
#define STSTRSIZE 80
#define STGROWSIZE 16
#define HOSTNMLEN 40
#define STSORT_PR 0
#define STSORT_PKTS 1
#define STSORT_BYTES 2
#define STSORT_TTL 3
#define STSORT_SRCIP 4
#define STSORT_SRCPT 5
#define STSORT_DSTIP 6
#define STSORT_DSTPT 7
#define STSORT_MAX STSORT_DSTPT
#define STSORT_DEFAULT STSORT_BYTES
typedef struct statetop {
} statetop_t;
#endif
#ifdef STATETOP
int, int, int));
static void sig_resize __P((int));
static char *ttl_to_string __P((long));
static int sort_bytes __P((const void *, const void *));
static int sort_srcip __P((const void *, const void *));
static int sort_srcpt __P((const void *, const void *));
static int sort_dstip __P((const void *, const void *));
static int sort_dstpt __P((const void *, const void *));
#endif
char *name;
{
#ifdef USE_INET6
#else
#endif
#ifdef USE_INET6
#else
#endif
exit(1);
}
int argc;
char *argv[];
{
int c, myoptind;
int topclosed = 0; /* do not show closed tcp sessions */
#ifdef USE_INET6
options = "6aACdfghIilnostvD:M:N:P:RS:T:";
#else
options = "aACdfghIilnostvD:M:N:P:RS:T:";
#endif
#ifdef USE_INET6
#endif
/* Don't warn about invalid flags when we run getopt for the 1st time */
opterr = 0;
/*
* Parse these two arguments now lest there be any buffer overflows
* in the parsing of the rest.
*/
switch (c)
{
case 'M' :
live_kernel = 0;
break;
case 'N' :
live_kernel = 0;
break;
}
}
if (live_kernel == 1) {
perror("open(IPSTATE_NAME)");
exit(-1);
}
perror("");
exit(-1);
}
}
exit(-1);
}
if (live_kernel == 1)
opterr = 1;
{
switch (c)
{
#ifdef USE_INET6
case '6' :
use_inet6 = 1;
break;
#endif
case 'a' :
break;
case 'A' :
opts |= OPT_AUTHSTATS;
break;
case 'C' :
topclosed = 1;
break;
case 'd' :
break;
case 'D' :
break;
case 'f' :
opts |= OPT_FRSTATES;
break;
case 'g' :
opts |= OPT_GROUPS;
break;
case 'h' :
break;
case 'i' :
break;
case 'I' :
opts |= OPT_INACTIVE;
break;
case 'l' :
opts |= OPT_SHOWLIST;
break;
case 'M' :
break;
case 'N' :
break;
case 'n' :
opts |= OPT_SHOWLINENO;
break;
case 'o' :
break;
case 'P' :
if (protocol == -1) {
exit(-2);
}
break;
case 'R' :
opts |= OPT_NORESOLVE;
break;
case 's' :
opts |= OPT_IPSTATES;
break;
case 'S' :
break;
case 't' :
#ifdef STATETOP
opts |= OPT_STATETOP;
break;
#else
"%s: state top facility not compiled in\n",
argv[0]);
exit(-2);
#endif
case 'T' :
(refreshtime <= 0)) {
"%s: Invalid refreshtime < 1 : %s\n",
exit(-2);
}
break;
case 'v' :
opts |= OPT_VERBOSE;
break;
default :
break;
}
}
if (live_kernel == 1) {
} else
if (opts & OPT_IPSTATES) {
} else if (opts & OPT_SHOWLIST) {
opts &= ~OPT_OUTQUE;
}
} else if (opts & OPT_FRSTATES)
#ifdef STATETOP
else if (opts & OPT_STATETOP)
#endif
else if (opts & OPT_AUTHSTATS)
else if (opts & OPT_GROUPS)
else
return 0;
}
/*
* Fill in the stats structures from the live kernel, using a combination
* of ioctl's and copying directly from kernel memory.
*/
char *device;
friostat_t **fiopp;
{
exit(1);
}
if ((opts & OPT_AUTHSTATS) == 0) {
perror("ioctl(ipf:SIOCGETFS)");
exit(-1);
}
perror("ioctl(SIOCGETFF)");
}
if ((opts & OPT_IPSTATES) != 0) {
perror("ioctl(state:SIOCGETFS)");
exit(-1);
}
perror("ioctl(state:SIOCGETLG)");
exit(-1);
}
}
if ((opts & OPT_FRSTATES) != 0) {
perror("ioctl(SIOCGFRST)");
exit(-1);
}
}
if (opts & OPT_VERBOSE)
if ((opts & OPT_AUTHSTATS) != 0) {
if (ipf_fd >= 0) {
ipf_fd = -1;
}
perror("open");
exit(-1);
}
perror("ioctl(SIOCATHST)");
exit(-1);
}
}
}
/*
* Build up the stats structures from data held in the "core" memory.
* This is mainly useful when looking at data in crash dumps and ioctl's
* just won't work any more.
*/
char *kernel;
friostat_t **fiopp;
{
int temp;
{ "fr_authstats" }, /* 0 */
{ "fae_list" },
{ "ipauth" },
{ "fr_authlist" },
{ "fr_authstart" },
{ "fr_authend" }, /* 5 */
{ "fr_authnext" },
{ "fr_auth" },
{ "fr_authused" },
{ "fr_authsize" },
{ "fr_defaultauthage" }, /* 10 */
{ "fr_authpkts" },
{ "fr_auth_lock" },
{ "frstats" },
{ "ips_stats" },
{ "ips_num" }, /* 15 */
{ "ips_wild" },
{ "ips_list" },
{ "ips_table" },
{ "fr_statemax" },
{ "fr_statesize" }, /* 20 */
{ "fr_state_doflush" },
{ "fr_state_lock" },
{ "ipfr_heads" },
{ "ipfr_nattab" },
{ "ipfr_stats" }, /* 25 */
{ "ipfr_inuse" },
{ "fr_ipfrttl" },
{ "fr_frag_lock" },
{ "ipfr_timer_id" },
{ "fr_nat_lock" }, /* 30 */
{ "ipfilter" },
{ "ipfilter6" },
{ "ipacct" },
{ "ipacct6" },
{ "ipl_frouteok" }, /* 35 */
{ "fr_running" },
{ "ipfgroups" },
{ "fr_active" },
{ "fr_pass" },
{ "fr_flags" }, /* 40 */
{ "ipstate_logging" },
{ NULL }
};
*frfp = 0;
*frauthstpp = frauthstp;
return;
}
/*
* This is for SIOCGETFF.
*/
/*
* f_locks is a combination of the lock variable from each part of
* ipfilter (state, auth, nat, fragments).
*/
/*
* Get pointers to each list of rules (active, inactive, in, out)
*/
/*
* Same for IPv6, except make them null if support for it is not
* being compiled in.
*/
#ifdef USE_INET6
#else
#endif
/*
* Now get accounting rules pointers.
*/
#ifdef USE_INET6
#else
#endif
/*
* A collection of "global" variables used inside the kernel which
* are all collected in friostat_t via ioctl.
*/
/*
* Build up the state information stats structure.
*/
/*
* Build up the authentiation information stats structure.
*/
sizeof(*frauthstp));
/*
* Build up the fragment information stats structure.
*/
sizeof(*ifrstp));
/*
*/
sizeof(state_logging));
}
/*
* Display the kernel stats for packets blocked and passed and other
* associated running totals which are kept.
*/
{
PRINTF("bad packets:\t\tin %lu\tout %lu\n",
#ifdef USE_INET6
PRINTF(" IPv6 packets:\t\tin %lu out %lu\n",
#endif
PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
PRINTF(" counted %lu short %lu\n",
PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu",
PRINTF(" counted %lu short %lu\n",
PRINTF(" input packets logged:\tblocked %lu passed %lu\n",
PRINTF("output packets logged:\tblocked %lu passed %lu\n",
PRINTF(" packets logged:\tinput %lu output %lu\n",
PRINTF(" log failures:\t\tinput %lu output %lu\n",
PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n",
PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n",
PRINTF("packet state(in):\tkept %lu\tlost %lu\n",
PRINTF("packet state(out):\tkept %lu\tlost %lu\n",
PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n",
PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n",
PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n",
PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n",
PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n",
PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n",
if (frf & FF_LOGPASS)
PRINTF("\tpackets passed through filter\n");
if (frf & FF_LOGBLOCK)
PRINTF("\tpackets blocked by filter\n");
if (frf & FF_LOGNOMATCH)
PRINTF("\tpackets not matched by filter\n");
if (!frf)
PRINTF("\tnone\n");
}
/*
* Print out a list of rules from the kernel, starting at the one passed.
*/
{
int n;
n = 0;
else
do {
perror("ioctl(SIOCIPFITER)");
return;
}
n++;
#ifdef USE_QUAD_T
#else
#endif
#ifdef USE_QUAD_T
#else
#endif
if (opts & OPT_SHOWLINENO)
PRINTF("@%d ", n);
}
g = calloc(1, sizeof(*g));
if (g != NULL) {
grtop = g;
grtail = g;
} else {
grtail = g;
}
}
}
free(g);
}
}
{
char *data;
int n;
n = 0;
do {
sizeof(fb)) == -1) {
perror("kmemcpy");
return;
}
perror("kmemcpy");
return;
}
}
}
n++;
#ifdef USE_QUAD_T
#else
#endif
#ifdef USE_QUAD_T
#else
#endif
if (opts & OPT_SHOWLINENO)
PRINTF("@%d ", n);
}
g = calloc(1, sizeof(*g));
if (g != NULL) {
grtop = g;
grtail = g;
} else {
grtail = g;
}
}
}
if (type == FR_T_CALLFUNC) {
"# callfunc: ");
}
free(g);
}
}
/*
* print out all of the asked for rule sets, using the stats struct as
* the base from which to get the pointers.
*/
{
int i, set;
if (opts & OPT_INACTIVE)
#ifdef USE_INET6
i = F_ACOUT;
i = F_ACIN;
} else
#endif
if (opts & OPT_OUTQUE) {
i = F_ACOUT;
i = F_ACIN;
} else {
return;
}
} else {
#ifdef USE_INET6
i = F_OUT;
i = F_IN;
} else
#endif
if (opts & OPT_OUTQUE) {
i = F_OUT;
i = F_IN;
} else
return;
}
if (opts & OPT_VERBOSE)
if (opts & OPT_VERBOSE)
if (!fp) {
return;
}
if (live_kernel == 1)
else
}
/*
* Display ipfilter stateful filtering information
*/
static void showipstates(ipsp)
{
int i, sz;
perror("malloc");
exit(1);
}
return;
}
/*
* If a list of states hasn't been asked for, only print out stats
*/
if (!(opts & OPT_SHOWLIST)) {
PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n",
PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu max bucket\n",
PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n",
PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n",
PRINTF("State logging %sabled\n",
PRINTF("\nState table bucket statistics:\n");
totallen = 0;
maxlen = 0;
for (i = 0; i < ipsp->iss_statesize; i++) {
}
PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n",
minlen);
PRINTF("\t%lu maximal length\n\t%.3f average length\n",
0.0);
#define ENTRIES_PER_LINE 5
if (opts & OPT_VERBOSE) {
PRINTF("\nCurrent bucket sizes :\n");
for (i = 0; i < ipsp->iss_statesize; i++) {
if ((i % ENTRIES_PER_LINE) == 0)
PRINTF("\t");
if ((i % ENTRIES_PER_LINE) ==
(ENTRIES_PER_LINE - 1))
PRINTF("\n");
else
PRINTF(" ");
}
PRINTF("\n");
}
PRINTF("\n");
return;
}
/*
* Print out all the state information currently held in the kernel.
*/
}
}
#ifdef STATETOP
static int handle_resize = 0, handle_break = 0;
int sport;
int dport;
int protocol;
int ver;
int refreshtime;
int topclosed;
{
const char *errstr = "";
struct timeval selecttimeout;
time_t t;
/* install signal handlers */
/* init ncurses stuff */
initscr();
cbreak();
noecho();
curs_set(0);
timeout(0);
/* init hostname */
/* init ipfobj_t stuff */
/* repeat until user aborts */
while ( 1 ) {
/* get state table */
errstr = "ioctl(SIOCGETFS)";
ret = -1;
goto out;
}
/* clear the history */
tsentry = -1;
/* reset max str len */
/* read the state table and store in tstable */
sizeof(ips)))
break;
continue;
continue;
}
#ifdef USE_INET6
continue;
}
#endif
/* check protocol */
continue;
/* check ports if protocol is TCP or UDP */
continue;
/* show closed TCP sessions ? */
continue;
/*
* if necessary make room for this state
* entry
*/
tsentry++;
maxtsentries * sizeof(statetop_t));
perror("realloc");
exit(-1);
}
}
/* fill structure */
if (forward) {
} else {
}
}
}
/* sort the array */
if (tsentry != -1) {
switch (sorting)
{
case STSORT_PR:
sizeof(statetop_t), sort_p);
break;
case STSORT_PKTS:
sizeof(statetop_t), sort_pkts);
break;
case STSORT_BYTES:
sizeof(statetop_t), sort_bytes);
break;
case STSORT_TTL:
sizeof(statetop_t), sort_ttl);
break;
case STSORT_SRCIP:
sizeof(statetop_t), sort_srcip);
break;
case STSORT_SRCPT:
sizeof(statetop_t), sort_srcpt);
break;
case STSORT_DSTIP:
sizeof(statetop_t), sort_dstip);
break;
case STSORT_DSTPT:
sizeof(statetop_t), sort_dstpt);
break;
default:
break;
}
}
/* handle window resizes */
if (handle_resize) {
endwin();
initscr();
cbreak();
noecho();
curs_set(0);
timeout(0);
redraw = 1;
handle_resize = 0;
}
/* stop program? */
if (handle_break)
break;
/* print title */
erase();
winy = 0;
printw(" ");
/* just for fun add a clock */
/*
* print the display filters, this is placed in the loop,
* because someday I might add code for changing these
* while the programming is running :-)
*/
if (sport >= 0)
else
if (dport >= 0)
else
if (protocol < 0)
else
switch (sorting)
{
case STSORT_PR:
break;
case STSORT_PKTS:
break;
case STSORT_BYTES:
break;
case STSORT_TTL:
break;
case STSORT_SRCIP:
break;
case STSORT_SRCPT:
break;
case STSORT_DSTIP:
break;
case STSORT_DSTPT:
break;
default:
break;
}
if (reverse)
winy += 2;
printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
/*
* For an IPv4 IP address we need at most 15 characters,
* 4 tuples of 3 digits, separated by 3 dots. Enforce this
* length, so the colums do not change positions based
* on the size of the IP address. This length makes the
* output fit in a 80 column terminal.
* We are lacking a good solution for IPv6 addresses (that
* can be longer that 15 characters), so we do not enforce
* a maximum on the IP field size.
*/
if (srclen < 15)
srclen = 15;
if (dstlen < 15)
dstlen = 15;
/* print column description */
winy += 2;
printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
"ST", "PR", "#pkts", "#bytes", "ttl");
/* print all the entries */
if (reverse)
for (i = 0; i <= tsentry; i++) {
} else {
}
winy++;
/* print state */
/* print protocol */
if (proto) {
} else {
}
/* just print icmp for IPv6-ICMP */
/* print #pkt/#bytes */
#ifdef USE_QUAD_T
#else
#endif
if (reverse)
tp--;
else
tp++;
}
/* screen data structure is filled, now update the screen */
if (redraw)
break;
if (redraw) {
redraw = 0;
}
/* wait for key press or a 1 second time out period */
selecttimeout.tv_usec = 0;
/* if key pressed, read all waiting keys */
if (c == ERR)
continue;
c = TOLOWER(c);
if (c == 'l') {
redraw = 1;
} else if (c == 'q') {
break;
} else if (c == 'r') {
} else if (c == 'b') {
forward = 0;
} else if (c == 'f') {
forward = 1;
} else if (c == 's') {
if (++sorting > STSORT_MAX)
sorting = 0;
}
}
} /* while */
out:
printw("\n");
refresh();
endwin();
if (ret != 0)
}
#endif
/*
* Show fragment cache information that's held in the kernel.
*/
static void showfrstates(ifsp)
{
int i;
/*
* print out the numeric statistics
*/
PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n",
PRINTF("\t%lu retrans\n\t%lu too short\n",
PRINTF("\t%lu no memory\n\t%lu already exist\n",
return;
/*
* Print out the contents (if any) of the fragment cache table.
*/
PRINTF("\n");
for (i = 0; i < IPFT_SIZE; i++)
sizeof(ifr)) == -1)
break;
}
/*
* Print out the contents (if any) of the NAT fragment cache table.
*/
return;
for (i = 0; i < IPFT_SIZE; i++)
sizeof(ifr)) == -1)
break;
}
}
/*
* Show stats on how auth within IPFilter has been used
*/
static void showauthstates(asp)
{
#ifdef USE_QUAD_T
printf("Authorisation hits: %qu\tmisses %qu\n",
#else
#endif
printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
asp->fas_sendok);
printf("queok %ld\nquefail %ld\nexpire %ld\n",
while (frap) {
break;
}
}
/*
* Display groups used for each of filter rules, accounting rules and
* authentication, separately.
*/
static void showgroups(fiop)
{
for (i = 0; i < 3; i++) {
break;
else
break;
else
}
}
const char *argument;
int *port;
{
char *s, *comma;
int ok = 0;
/* make working copy of argument, Theoretically you must be able
* to write to optarg, but that seems very ugly to me....
*/
if (s == NULL)
return;
/* get port */
*port = -1;
argument);
free(s);
exit(-2);
}
*comma = '\0';
}
/* get ip address */
if (!strcasecmp(s, "any")) {
#ifdef USE_INET6
ok = 1;
#endif
ok = 1;
if (ok == 0) {
free(s);
exit(-2);
}
/* free allocated memory */
free(s);
}
#ifdef STATETOP
static void sig_resize(s)
int s;
{
handle_resize = 1;
}
static void sig_break(s)
int s;
{
handle_break = 1;
}
int v;
{
#ifdef USE_INET6
#endif
if (v == 4)
#ifdef USE_INET6
return hostbuf;
#else
return "IPv6";
#endif
}
static char *ttl_to_string(ttl)
long int ttl;
{
/* ttl is in half seconds */
ttl /= 2;
if (hours > 0)
else
return ttlbuf;
}
static int sort_pkts(a, b)
const void *a;
const void *b;
{
register const statetop_t *ap = a;
register const statetop_t *bp = b;
return 0;
return 1;
return -1;
}
static int sort_bytes(a, b)
const void *a;
const void *b;
{
register const statetop_t *ap = a;
register const statetop_t *bp = b;
return 0;
return 1;
return -1;
}
static int sort_p(a, b)
const void *a;
const void *b;
{
register const statetop_t *ap = a;
register const statetop_t *bp = b;
return 0;
return 1;
return -1;
}
static int sort_ttl(a, b)
const void *a;
const void *b;
{
register const statetop_t *ap = a;
register const statetop_t *bp = b;
return 0;
return 1;
return -1;
}
static int sort_srcip(a, b)
const void *a;
const void *b;
{
register const statetop_t *ap = a;
register const statetop_t *bp = b;
#ifdef USE_INET6
if (use_inet6) {
return 0;
return 1;
} else
#endif
{
return 0;
return 1;
}
return -1;
}
static int sort_srcpt(a, b)
const void *a;
const void *b;
{
register const statetop_t *ap = a;
register const statetop_t *bp = b;
return 0;
return 1;
return -1;
}
static int sort_dstip(a, b)
const void *a;
const void *b;
{
register const statetop_t *ap = a;
register const statetop_t *bp = b;
#ifdef USE_INET6
if (use_inet6) {
return 0;
return 1;
} else
#endif
{
return 0;
return 1;
}
return -1;
}
static int sort_dstpt(a, b)
const void *a;
const void *b;
{
register const statetop_t *ap = a;
register const statetop_t *bp = b;
return 0;
return 1;
return -1;
}
#endif