xref: /openbsd-src/usr.bin/systat/pf.c (revision 19e99d061340840dc52e10ae9c02d78a0a455689)
1*19e99d06Sbluhm /*	$OpenBSD: pf.c,v 1.14 2024/04/22 13:30:22 bluhm Exp $ */
273baed14Scanacar /*
373baed14Scanacar  * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
473baed14Scanacar  *
573baed14Scanacar  * Permission to use, copy, modify, and distribute this software for any
673baed14Scanacar  * purpose with or without fee is hereby granted, provided that the above
773baed14Scanacar  * copyright notice and this permission notice appear in all copies.
873baed14Scanacar  *
973baed14Scanacar  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1073baed14Scanacar  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1173baed14Scanacar  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1273baed14Scanacar  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1373baed14Scanacar  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1473baed14Scanacar  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1573baed14Scanacar  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1673baed14Scanacar  */
1773baed14Scanacar 
1873baed14Scanacar #include <sys/types.h>
197ac01546Sclaudio #include <sys/sysctl.h>
2073baed14Scanacar #include <sys/ioctl.h>
2173baed14Scanacar #include <sys/socket.h>
228f6b3bafSderaadt #include <sys/signal.h>
2373baed14Scanacar #include <net/if.h>
2473baed14Scanacar #include <netinet/in.h>
2573baed14Scanacar #include <netinet/ip.h>
2673baed14Scanacar #include <net/pfvar.h>
2773baed14Scanacar 
2873baed14Scanacar #include <stdio.h>
2973baed14Scanacar #include <stdlib.h>
3073baed14Scanacar #include <string.h>
3173baed14Scanacar #include <ctype.h>
3273baed14Scanacar #include <errno.h>
3373baed14Scanacar #include <err.h>
3473baed14Scanacar #include <unistd.h>
3527b150ceSmcbride #include <syslog.h>
3673baed14Scanacar #include "pfctl_parser.h"
3773baed14Scanacar #include "systat.h"
3873baed14Scanacar 
3973baed14Scanacar void print_pf(void);
4073baed14Scanacar int read_pf(void);
4173baed14Scanacar int select_pf(void);
423e286cffSlum void print_fld_double(field_def *, double);
4373baed14Scanacar 
4473baed14Scanacar const char	*pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
4573baed14Scanacar const char	*pf_lcounters[LCNT_MAX+1] = LCNT_NAMES;
4673baed14Scanacar const char	*pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
47*19e99d06Sbluhm const char	*pf_scounters[SCNT_MAX+1] = FCNT_NAMES;
48*19e99d06Sbluhm const char	*pf_ncounters[NCNT_MAX+1] = FCNT_NAMES;
4973baed14Scanacar 
5073baed14Scanacar static struct pf_status status;
5173baed14Scanacar int num_pf = 0;
5273baed14Scanacar 
5373baed14Scanacar field_def fields_pf[] = {
5473baed14Scanacar 	{"TYPE", 13, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
5573baed14Scanacar 	{"NAME", 12, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
5673baed14Scanacar 	{"VALUE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
5773baed14Scanacar 	{"RATE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 60},
5873baed14Scanacar };
5973baed14Scanacar 
60596a8091Sjasper #define FLD_PF_TYPE	FIELD_ADDR(fields_pf,0)
61596a8091Sjasper #define FLD_PF_NAME	FIELD_ADDR(fields_pf,1)
62596a8091Sjasper #define FLD_PF_VALUE	FIELD_ADDR(fields_pf,2)
63596a8091Sjasper #define FLD_PF_RATE	FIELD_ADDR(fields_pf,3)
6473baed14Scanacar 
6573baed14Scanacar /* Define views */
6673baed14Scanacar field_def *view_pf_0[] = {
67a86169ecSkn 	FLD_PF_TYPE, FLD_PF_NAME, FLD_PF_VALUE, FLD_PF_RATE, NULL
6873baed14Scanacar };
6973baed14Scanacar 
7073baed14Scanacar 
7173baed14Scanacar /* Define view managers */
7273baed14Scanacar struct view_manager pf_mgr = {
7373baed14Scanacar 	"PF", select_pf, read_pf, NULL, print_header,
7473baed14Scanacar 	print_pf, keyboard_callback, NULL, NULL
7573baed14Scanacar };
7673baed14Scanacar 
7773baed14Scanacar field_view views_pf[] = {
7873baed14Scanacar 	{view_pf_0, "pf", 'P', &pf_mgr},
7973baed14Scanacar 	{NULL, NULL, 0, NULL}
8073baed14Scanacar };
8173baed14Scanacar 
8273baed14Scanacar 
8373baed14Scanacar 
8473baed14Scanacar int
select_pf(void)8573baed14Scanacar select_pf(void)
8673baed14Scanacar {
8773baed14Scanacar 	return (0);
8873baed14Scanacar }
8973baed14Scanacar 
9073baed14Scanacar int
read_pf(void)9173baed14Scanacar read_pf(void)
9273baed14Scanacar {
937ac01546Sclaudio 	size_t size = sizeof(status);
947ac01546Sclaudio 	int mib[3] = { CTL_KERN, KERN_PFSTATUS };
9573baed14Scanacar 
963aaa63ebSderaadt 	if (sysctl(mib, 2, &status, &size, NULL, 0) == -1) {
977ac01546Sclaudio 		error("sysctl(PFCTL_STATUS): %s", strerror(errno));
9873baed14Scanacar 		return (-1);
9973baed14Scanacar 	}
10073baed14Scanacar 
10173baed14Scanacar 	num_disp = 4;
10273baed14Scanacar 
10373baed14Scanacar 	if (status.ifname[0] != 0)
10473baed14Scanacar 		num_disp += 13;
10573baed14Scanacar 
10673baed14Scanacar 	num_disp += FCNT_MAX + 2;
10773baed14Scanacar 	num_disp += SCNT_MAX + 2;
108*19e99d06Sbluhm 	num_disp += NCNT_MAX + 2;
10973baed14Scanacar 	num_disp += PFRES_MAX + 1;
11073baed14Scanacar 	num_disp += LCNT_MAX + 1;
11173baed14Scanacar 
11273baed14Scanacar 	return (0);
11373baed14Scanacar }
11473baed14Scanacar 
11573baed14Scanacar int
initpf(void)11673baed14Scanacar initpf(void)
11773baed14Scanacar {
11873baed14Scanacar 	field_view *v;
11973baed14Scanacar 
12073baed14Scanacar 	for (v = views_pf; v->name != NULL; v++)
12173baed14Scanacar 		add_view(v);
12273baed14Scanacar 
12373baed14Scanacar 	return(1);
12473baed14Scanacar }
12573baed14Scanacar 
12673baed14Scanacar void
print_fld_double(field_def * fld,double val)12773baed14Scanacar print_fld_double(field_def *fld, double val)
12873baed14Scanacar {
12973baed14Scanacar 	int len;
13073baed14Scanacar 
13173baed14Scanacar 	if (fld == NULL)
13273baed14Scanacar 		return;
13373baed14Scanacar 
13473baed14Scanacar 	len = fld->width;
13573baed14Scanacar 	if (len < 1)
13673baed14Scanacar 		return;
13773baed14Scanacar 
13873baed14Scanacar 	tb_start();
13973baed14Scanacar 	if (tbprintf("%.2f", val) > len)
14073baed14Scanacar 		print_fld_str(fld, "*");
14173baed14Scanacar 	else
14273baed14Scanacar 		print_fld_tb(fld);
14373baed14Scanacar 	tb_end();
14473baed14Scanacar }
14573baed14Scanacar 
14673baed14Scanacar #define ADD_LINE_A(t, n, v) \
14773baed14Scanacar 	do {							\
14873baed14Scanacar 		if (cur >= dispstart && cur < end) { 		\
14973baed14Scanacar 			print_fld_str(FLD_PF_TYPE, (t));	\
15073baed14Scanacar 			print_fld_str(FLD_PF_NAME, (n));	\
15173baed14Scanacar 			print_fld_age(FLD_PF_VALUE, (v));	\
15273baed14Scanacar 			end_line();				\
15373baed14Scanacar 		}						\
15473baed14Scanacar 		if (++cur >= end)				\
15573baed14Scanacar 			return;					\
15673baed14Scanacar 	} while (0)
15773baed14Scanacar 
15873baed14Scanacar #define ADD_EMPTY_LINE \
15973baed14Scanacar 	do {							\
16073baed14Scanacar 		if (cur >= dispstart && cur < end) 		\
16173baed14Scanacar 			end_line();				\
16273baed14Scanacar 		if (++cur >= end)				\
16373baed14Scanacar 			return;					\
16473baed14Scanacar 	} while (0)
16573baed14Scanacar 
16673baed14Scanacar #define ADD_LINE_S(t, n, v) \
16773baed14Scanacar 	do {							\
16873baed14Scanacar 		if (cur >= dispstart && cur < end) { 		\
16973baed14Scanacar 			print_fld_str(FLD_PF_TYPE, (t));	\
17073baed14Scanacar 			print_fld_str(FLD_PF_NAME, (n));	\
17173baed14Scanacar 			print_fld_str(FLD_PF_VALUE, (v));	\
17273baed14Scanacar 			end_line();				\
17373baed14Scanacar 		}						\
17473baed14Scanacar 		if (++cur >= end)				\
17573baed14Scanacar 			return;					\
17673baed14Scanacar 	} while (0)
17773baed14Scanacar 
17873baed14Scanacar #define ADD_LINE_V(t, n, v) \
17973baed14Scanacar 	do {							\
18073baed14Scanacar 		if (cur >= dispstart && cur < end) { 		\
18173baed14Scanacar 			print_fld_str(FLD_PF_TYPE, (t));	\
18273baed14Scanacar 			print_fld_str(FLD_PF_NAME, (n));	\
18373baed14Scanacar 			print_fld_size(FLD_PF_VALUE, (v));	\
18473baed14Scanacar 			end_line();				\
18573baed14Scanacar 		}						\
18673baed14Scanacar 		if (++cur >= end)				\
18773baed14Scanacar 			return;					\
18873baed14Scanacar 	} while (0)
18973baed14Scanacar 
19073baed14Scanacar #define ADD_LINE_VR(t, n, v, r) \
19173baed14Scanacar 	do {							\
19273baed14Scanacar 		if (cur >= dispstart && cur < end) { 		\
19373baed14Scanacar 			print_fld_str(FLD_PF_TYPE, (t));	\
19473baed14Scanacar 			print_fld_str(FLD_PF_NAME, (n));	\
19573baed14Scanacar 			print_fld_size(FLD_PF_VALUE, (v));	\
19673baed14Scanacar 			print_fld_double(FLD_PF_RATE, (r));	\
19773baed14Scanacar 			end_line();				\
19873baed14Scanacar 		}						\
19973baed14Scanacar 		if (++cur >= end)				\
20073baed14Scanacar 			return;					\
20173baed14Scanacar 	} while (0)
20273baed14Scanacar 
20373baed14Scanacar 
20473baed14Scanacar void
print_pf(void)20573baed14Scanacar print_pf(void)
20673baed14Scanacar {
20773baed14Scanacar 	char		*debug;
20863b24bdaSpatrick 	time_t		tm = 0;
20963b24bdaSpatrick 	struct timespec	uptime;
21073baed14Scanacar 	int		i;
21173baed14Scanacar 	struct pf_status *s = &status;
21273baed14Scanacar 
21373baed14Scanacar 	int cur = 0;
21473baed14Scanacar 	int end = dispstart + maxprint;
21573baed14Scanacar 	if (end > num_disp)
21673baed14Scanacar 		end = num_disp;
21773baed14Scanacar 
218e45b97acScheloha 	if (!clock_gettime(CLOCK_BOOTTIME, &uptime))
21963b24bdaSpatrick 		tm = uptime.tv_sec - s->since;
22073baed14Scanacar 
22173baed14Scanacar 	ADD_LINE_S("pf", "Status", s->running ? "Enabled" : "Disabled");
22273baed14Scanacar 	ADD_LINE_A("pf", "Since", tm);
22373baed14Scanacar 
22473baed14Scanacar 	switch (s->debug) {
22527b150ceSmcbride 	case LOG_EMERG:
22627b150ceSmcbride 		debug = "emerg";
22773baed14Scanacar 		break;
22827b150ceSmcbride 	case LOG_ALERT:
22927b150ceSmcbride 		debug = "alert";
23073baed14Scanacar 		break;
23127b150ceSmcbride 	case LOG_CRIT:
23227b150ceSmcbride 		debug = "crit";
23373baed14Scanacar 		break;
23427b150ceSmcbride 	case LOG_ERR:
23527b150ceSmcbride 		debug = "err";
23627b150ceSmcbride 		break;
23727b150ceSmcbride 	case LOG_WARNING:
23827b150ceSmcbride 		debug = "warning";
23927b150ceSmcbride 		break;
24027b150ceSmcbride 	case LOG_NOTICE:
24127b150ceSmcbride 		debug = "notice";
24227b150ceSmcbride 		break;
24327b150ceSmcbride 	case LOG_INFO:
24427b150ceSmcbride 		debug = "info";
24527b150ceSmcbride 		break;
24627b150ceSmcbride 	case LOG_DEBUG:
24727b150ceSmcbride 		debug = "debug";
24873baed14Scanacar 		break;
249bff63f6aSbenno 	default:
250bff63f6aSbenno 		debug = "unknown";
251bff63f6aSbenno 		break;
25273baed14Scanacar 	}
25373baed14Scanacar 	ADD_LINE_S("pf", "Debug", debug);
25473baed14Scanacar 
25573baed14Scanacar 	tb_start();
25673baed14Scanacar 	tbprintf("0x%08x\n", ntohl(s->hostid));
25773baed14Scanacar 	tb_end();
25873baed14Scanacar 
25973baed14Scanacar 	ADD_LINE_S("pf", "Hostid", tmp_buf);
26073baed14Scanacar 
26173baed14Scanacar 	if (s->ifname[0] != 0) {
26273baed14Scanacar 		ADD_EMPTY_LINE;
263a86169ecSkn 		ADD_LINE_V(s->ifname, "Bytes In IPv4", s->bcounters[0][0]);
264a86169ecSkn 		ADD_LINE_V(s->ifname, "Bytes In IPv6", s->bcounters[1][0]);
265a86169ecSkn 		ADD_LINE_V(s->ifname, "Bytes Out IPv4", s->bcounters[0][1]);
266a86169ecSkn 		ADD_LINE_V(s->ifname, "Bytes Out IPv6", s->bcounters[1][1]);
267a86169ecSkn 		ADD_LINE_V(s->ifname, "Packets In Passed IPv4", s->pcounters[0][0][PF_PASS]);
268a86169ecSkn 		ADD_LINE_V(s->ifname, "Packets In Passed IPv6", s->pcounters[1][0][PF_PASS]);
269a86169ecSkn 		ADD_LINE_V(s->ifname, "Packets In Blocked IPv4", s->pcounters[0][0][PF_DROP]);
270a86169ecSkn 		ADD_LINE_V(s->ifname, "Packets In Blocked IPv6", s->pcounters[1][0][PF_DROP]);
271a86169ecSkn 		ADD_LINE_V(s->ifname, "Packets Out Passed IPv4", s->pcounters[0][1][PF_PASS]);
272a86169ecSkn 		ADD_LINE_V(s->ifname, "Packets Out Passed IPv6", s->pcounters[1][1][PF_PASS]);
273a86169ecSkn 		ADD_LINE_V(s->ifname, "Packets Out Blocked IPv4", s->pcounters[0][1][PF_DROP]);
274a86169ecSkn 		ADD_LINE_V(s->ifname, "Packets Out Blocked IPv6", s->pcounters[1][1][PF_DROP]);
27573baed14Scanacar 	}
27673baed14Scanacar 
27773baed14Scanacar 
27873baed14Scanacar 	ADD_EMPTY_LINE;
27973baed14Scanacar 	ADD_LINE_V("state", "Count", s->states);
28073baed14Scanacar 
28173baed14Scanacar 	for (i = 0; i < FCNT_MAX; i++) {
28273baed14Scanacar 		if (tm > 0)
28373baed14Scanacar 			ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i],
28473baed14Scanacar 				    (double)s->fcounters[i] / (double)tm);
28573baed14Scanacar 		else
28673baed14Scanacar 			ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]);
28773baed14Scanacar 	}
28873baed14Scanacar 
28973baed14Scanacar 
29073baed14Scanacar 	ADD_EMPTY_LINE;
29173baed14Scanacar 	ADD_LINE_V("src track", "Count", s->src_nodes);
29273baed14Scanacar 
29373baed14Scanacar 	for (i = 0; i < SCNT_MAX; i++) {
29473baed14Scanacar 		if (tm > 0)
29573baed14Scanacar 			ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i],
29673baed14Scanacar 				    (double)s->scounters[i] / (double)tm);
29773baed14Scanacar 		else
29873baed14Scanacar 			ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]);
29973baed14Scanacar 	}
30073baed14Scanacar 
30173baed14Scanacar 	ADD_EMPTY_LINE;
302*19e99d06Sbluhm 	ADD_LINE_V("fragment", "Count", s->fragments);
303*19e99d06Sbluhm 
304*19e99d06Sbluhm 	for (i = 0; i < NCNT_MAX; i++) {
305*19e99d06Sbluhm 		if (tm > 0)
306*19e99d06Sbluhm 			ADD_LINE_VR("fragment", pf_ncounters[i], s->ncounters[i],
307*19e99d06Sbluhm 				    (double)s->ncounters[i] / (double)tm);
308*19e99d06Sbluhm 		else
309*19e99d06Sbluhm 			ADD_LINE_V("fragment", pf_ncounters[i], s->ncounters[i]);
310*19e99d06Sbluhm 	}
311*19e99d06Sbluhm 
312*19e99d06Sbluhm 	ADD_EMPTY_LINE;
31373baed14Scanacar 	for (i = 0; i < PFRES_MAX; i++) {
31473baed14Scanacar 		if (tm > 0)
31573baed14Scanacar 			ADD_LINE_VR("counter", pf_reasons[i], s->counters[i],
31673baed14Scanacar 				    (double)s->counters[i] / (double)tm);
31773baed14Scanacar 		else
31873baed14Scanacar 			ADD_LINE_V("counter", pf_reasons[i], s->counters[i]);
31973baed14Scanacar 	}
32073baed14Scanacar 
32173baed14Scanacar 	ADD_EMPTY_LINE;
32273baed14Scanacar 	for (i = 0; i < LCNT_MAX; i++) {
32373baed14Scanacar 		if (tm > 0)
32473baed14Scanacar 			ADD_LINE_VR("limit counter", pf_lcounters[i], s->lcounters[i],
32573baed14Scanacar 				    (double)s->lcounters[i] / (double)tm);
32673baed14Scanacar 		else
32773baed14Scanacar 			ADD_LINE_V("limit counter", pf_lcounters[i], s->lcounters[i]);
32873baed14Scanacar 	}
32973baed14Scanacar }
330