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