[BACK]Return to pf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / systat

File: [local] / src / usr.bin / systat / pf.c (download)

Revision 1.14, Mon Apr 22 13:30:22 2024 UTC (3 weeks, 5 days ago) by bluhm
Branch: MAIN
CVS Tags: HEAD
Changes since 1.13: +15 -2 lines

Show pf fragment reassembly counters.

Framgent count and statistics are stored in struct pf_status.  From
there pfctl(8) and systat(1) collect and show them.  Note that pfctl
-s info needs the -v switch to show fragments.  As fragment reassembly
has its own mutex, also grab this in pf ipctl(2) and sysctl(2) code.

input claudio@; OK henning@

/*	$OpenBSD: pf.c,v 1.14 2024/04/22 13:30:22 bluhm Exp $ */
/*
 * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <net/pfvar.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <err.h>
#include <unistd.h>
#include <syslog.h>
#include "pfctl_parser.h"
#include "systat.h"

void print_pf(void);
int read_pf(void);
int select_pf(void);
void print_fld_double(field_def *, double);

const char	*pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
const char	*pf_lcounters[LCNT_MAX+1] = LCNT_NAMES;
const char	*pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
const char	*pf_scounters[SCNT_MAX+1] = FCNT_NAMES;
const char	*pf_ncounters[NCNT_MAX+1] = FCNT_NAMES;

static struct pf_status status;
int num_pf = 0;

field_def fields_pf[] = {
	{"TYPE", 13, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"NAME", 12, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
	{"VALUE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"RATE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 60},
};

#define FLD_PF_TYPE	FIELD_ADDR(fields_pf,0)
#define FLD_PF_NAME	FIELD_ADDR(fields_pf,1)
#define FLD_PF_VALUE	FIELD_ADDR(fields_pf,2)
#define FLD_PF_RATE	FIELD_ADDR(fields_pf,3)

/* Define views */
field_def *view_pf_0[] = {
	FLD_PF_TYPE, FLD_PF_NAME, FLD_PF_VALUE, FLD_PF_RATE, NULL
};


/* Define view managers */
struct view_manager pf_mgr = {
	"PF", select_pf, read_pf, NULL, print_header,
	print_pf, keyboard_callback, NULL, NULL
};

field_view views_pf[] = {
	{view_pf_0, "pf", 'P', &pf_mgr},
	{NULL, NULL, 0, NULL}
};



int
select_pf(void)
{
	return (0);
}

int
read_pf(void)
{
	size_t size = sizeof(status);
	int mib[3] = { CTL_KERN, KERN_PFSTATUS };

	if (sysctl(mib, 2, &status, &size, NULL, 0) == -1) {
		error("sysctl(PFCTL_STATUS): %s", strerror(errno));
		return (-1);
	}

	num_disp = 4;

	if (status.ifname[0] != 0)
		num_disp += 13;

	num_disp += FCNT_MAX + 2;
	num_disp += SCNT_MAX + 2;
	num_disp += NCNT_MAX + 2;
	num_disp += PFRES_MAX + 1;
	num_disp += LCNT_MAX + 1;

	return (0);
}

int
initpf(void)
{
	field_view *v;

	for (v = views_pf; v->name != NULL; v++)
		add_view(v);

	return(1);
}

void
print_fld_double(field_def *fld, double val)
{
	int len;

	if (fld == NULL)
		return;

	len = fld->width;
	if (len < 1)
		return;

	tb_start();
	if (tbprintf("%.2f", val) > len)
		print_fld_str(fld, "*");
	else
		print_fld_tb(fld);
	tb_end();
}

#define ADD_LINE_A(t, n, v) \
	do {							\
		if (cur >= dispstart && cur < end) { 		\
			print_fld_str(FLD_PF_TYPE, (t));	\
			print_fld_str(FLD_PF_NAME, (n));	\
			print_fld_age(FLD_PF_VALUE, (v));	\
			end_line();				\
		}						\
		if (++cur >= end)				\
			return;					\
	} while (0)

#define ADD_EMPTY_LINE \
	do {							\
		if (cur >= dispstart && cur < end) 		\
			end_line();				\
		if (++cur >= end)				\
			return;					\
	} while (0)

#define ADD_LINE_S(t, n, v) \
	do {							\
		if (cur >= dispstart && cur < end) { 		\
			print_fld_str(FLD_PF_TYPE, (t));	\
			print_fld_str(FLD_PF_NAME, (n));	\
			print_fld_str(FLD_PF_VALUE, (v));	\
			end_line();				\
		}						\
		if (++cur >= end)				\
			return;					\
	} while (0)

#define ADD_LINE_V(t, n, v) \
	do {							\
		if (cur >= dispstart && cur < end) { 		\
			print_fld_str(FLD_PF_TYPE, (t));	\
			print_fld_str(FLD_PF_NAME, (n));	\
			print_fld_size(FLD_PF_VALUE, (v));	\
			end_line();				\
		}						\
		if (++cur >= end)				\
			return;					\
	} while (0)

#define ADD_LINE_VR(t, n, v, r) \
	do {							\
		if (cur >= dispstart && cur < end) { 		\
			print_fld_str(FLD_PF_TYPE, (t));	\
			print_fld_str(FLD_PF_NAME, (n));	\
			print_fld_size(FLD_PF_VALUE, (v));	\
			print_fld_double(FLD_PF_RATE, (r));	\
			end_line();				\
		}						\
		if (++cur >= end)				\
			return;					\
	} while (0)


void
print_pf(void)
{
	char		*debug;
	time_t		tm = 0;
	struct timespec	uptime;
	int		i;
	struct pf_status *s = &status;

	int cur = 0;
	int end = dispstart + maxprint;
	if (end > num_disp)
		end = num_disp;

	if (!clock_gettime(CLOCK_BOOTTIME, &uptime))
		tm = uptime.tv_sec - s->since;

	ADD_LINE_S("pf", "Status", s->running ? "Enabled" : "Disabled");
	ADD_LINE_A("pf", "Since", tm);

	switch (s->debug) {
	case LOG_EMERG:
		debug = "emerg";
		break;
	case LOG_ALERT:
		debug = "alert";
		break;
	case LOG_CRIT:
		debug = "crit";
		break;
	case LOG_ERR:
		debug = "err";
		break;
	case LOG_WARNING:
		debug = "warning";
		break;
	case LOG_NOTICE:
		debug = "notice";
		break;
	case LOG_INFO:
		debug = "info";
		break;
	case LOG_DEBUG:
		debug = "debug";
		break;
	default:
		debug = "unknown";
		break;		
	}
	ADD_LINE_S("pf", "Debug", debug);

	tb_start();
	tbprintf("0x%08x\n", ntohl(s->hostid));
	tb_end();

	ADD_LINE_S("pf", "Hostid", tmp_buf);

	if (s->ifname[0] != 0) {
		ADD_EMPTY_LINE;
		ADD_LINE_V(s->ifname, "Bytes In IPv4", s->bcounters[0][0]);
		ADD_LINE_V(s->ifname, "Bytes In IPv6", s->bcounters[1][0]);
		ADD_LINE_V(s->ifname, "Bytes Out IPv4", s->bcounters[0][1]);
		ADD_LINE_V(s->ifname, "Bytes Out IPv6", s->bcounters[1][1]);
		ADD_LINE_V(s->ifname, "Packets In Passed IPv4", s->pcounters[0][0][PF_PASS]);
		ADD_LINE_V(s->ifname, "Packets In Passed IPv6", s->pcounters[1][0][PF_PASS]);
		ADD_LINE_V(s->ifname, "Packets In Blocked IPv4", s->pcounters[0][0][PF_DROP]);
		ADD_LINE_V(s->ifname, "Packets In Blocked IPv6", s->pcounters[1][0][PF_DROP]);
		ADD_LINE_V(s->ifname, "Packets Out Passed IPv4", s->pcounters[0][1][PF_PASS]);
		ADD_LINE_V(s->ifname, "Packets Out Passed IPv6", s->pcounters[1][1][PF_PASS]);
		ADD_LINE_V(s->ifname, "Packets Out Blocked IPv4", s->pcounters[0][1][PF_DROP]);
		ADD_LINE_V(s->ifname, "Packets Out Blocked IPv6", s->pcounters[1][1][PF_DROP]);
	}


	ADD_EMPTY_LINE;
	ADD_LINE_V("state", "Count", s->states);

	for (i = 0; i < FCNT_MAX; i++) {
		if (tm > 0)
			ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i],
				    (double)s->fcounters[i] / (double)tm);
		else
			ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]);
	}


	ADD_EMPTY_LINE;
	ADD_LINE_V("src track", "Count", s->src_nodes);

	for (i = 0; i < SCNT_MAX; i++) {
		if (tm > 0)
			ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i],
				    (double)s->scounters[i] / (double)tm);
		else
			ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]);
	}

	ADD_EMPTY_LINE;
	ADD_LINE_V("fragment", "Count", s->fragments);

	for (i = 0; i < NCNT_MAX; i++) {
		if (tm > 0)
			ADD_LINE_VR("fragment", pf_ncounters[i], s->ncounters[i],
				    (double)s->ncounters[i] / (double)tm);
		else
			ADD_LINE_V("fragment", pf_ncounters[i], s->ncounters[i]);
	}

	ADD_EMPTY_LINE;
	for (i = 0; i < PFRES_MAX; i++) {
		if (tm > 0)
			ADD_LINE_VR("counter", pf_reasons[i], s->counters[i],
				    (double)s->counters[i] / (double)tm);
		else
			ADD_LINE_V("counter", pf_reasons[i], s->counters[i]);
	}

	ADD_EMPTY_LINE;
	for (i = 0; i < LCNT_MAX; i++) {
		if (tm > 0)
			ADD_LINE_VR("limit counter", pf_lcounters[i], s->lcounters[i],
				    (double)s->lcounters[i] / (double)tm);
		else
			ADD_LINE_V("limit counter", pf_lcounters[i], s->lcounters[i]);
	}
}