xref: /openbsd/usr.bin/systat/pf.c (revision 4bdff4be)
1 /*	$OpenBSD: pf.c,v 1.13 2020/09/14 11:15:30 kn Exp $ */
2 /*
3  * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/sysctl.h>
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <sys/signal.h>
23 #include <net/if.h>
24 #include <netinet/in.h>
25 #include <netinet/ip.h>
26 #include <net/pfvar.h>
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <err.h>
34 #include <unistd.h>
35 #include <syslog.h>
36 #include "pfctl_parser.h"
37 #include "systat.h"
38 
39 void print_pf(void);
40 int read_pf(void);
41 int select_pf(void);
42 void print_fld_double(field_def *, double);
43 
44 const char	*pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
45 const char	*pf_lcounters[LCNT_MAX+1] = LCNT_NAMES;
46 const char	*pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
47 const char	*pf_scounters[FCNT_MAX+1] = FCNT_NAMES;
48 
49 static struct pf_status status;
50 int num_pf = 0;
51 
52 field_def fields_pf[] = {
53 	{"TYPE", 13, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
54 	{"NAME", 12, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
55 	{"VALUE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
56 	{"RATE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 60},
57 };
58 
59 #define FLD_PF_TYPE	FIELD_ADDR(fields_pf,0)
60 #define FLD_PF_NAME	FIELD_ADDR(fields_pf,1)
61 #define FLD_PF_VALUE	FIELD_ADDR(fields_pf,2)
62 #define FLD_PF_RATE	FIELD_ADDR(fields_pf,3)
63 
64 /* Define views */
65 field_def *view_pf_0[] = {
66 	FLD_PF_TYPE, FLD_PF_NAME, FLD_PF_VALUE, FLD_PF_RATE, NULL
67 };
68 
69 
70 /* Define view managers */
71 struct view_manager pf_mgr = {
72 	"PF", select_pf, read_pf, NULL, print_header,
73 	print_pf, keyboard_callback, NULL, NULL
74 };
75 
76 field_view views_pf[] = {
77 	{view_pf_0, "pf", 'P', &pf_mgr},
78 	{NULL, NULL, 0, NULL}
79 };
80 
81 
82 
83 int
84 select_pf(void)
85 {
86 	return (0);
87 }
88 
89 int
90 read_pf(void)
91 {
92 	size_t size = sizeof(status);
93 	int mib[3] = { CTL_KERN, KERN_PFSTATUS };
94 
95 	if (sysctl(mib, 2, &status, &size, NULL, 0) == -1) {
96 		error("sysctl(PFCTL_STATUS): %s", strerror(errno));
97 		return (-1);
98 	}
99 
100 	num_disp = 4;
101 
102 	if (status.ifname[0] != 0)
103 		num_disp += 13;
104 
105 	num_disp += FCNT_MAX + 2;
106 	num_disp += SCNT_MAX + 2;
107 	num_disp += PFRES_MAX + 1;
108 	num_disp += LCNT_MAX + 1;
109 
110 	return (0);
111 }
112 
113 int
114 initpf(void)
115 {
116 	field_view *v;
117 
118 	for (v = views_pf; v->name != NULL; v++)
119 		add_view(v);
120 
121 	return(1);
122 }
123 
124 void
125 print_fld_double(field_def *fld, double val)
126 {
127 	int len;
128 
129 	if (fld == NULL)
130 		return;
131 
132 	len = fld->width;
133 	if (len < 1)
134 		return;
135 
136 	tb_start();
137 	if (tbprintf("%.2f", val) > len)
138 		print_fld_str(fld, "*");
139 	else
140 		print_fld_tb(fld);
141 	tb_end();
142 }
143 
144 #define ADD_LINE_A(t, n, v) \
145 	do {							\
146 		if (cur >= dispstart && cur < end) { 		\
147 			print_fld_str(FLD_PF_TYPE, (t));	\
148 			print_fld_str(FLD_PF_NAME, (n));	\
149 			print_fld_age(FLD_PF_VALUE, (v));	\
150 			end_line();				\
151 		}						\
152 		if (++cur >= end)				\
153 			return;					\
154 	} while (0)
155 
156 #define ADD_EMPTY_LINE \
157 	do {							\
158 		if (cur >= dispstart && cur < end) 		\
159 			end_line();				\
160 		if (++cur >= end)				\
161 			return;					\
162 	} while (0)
163 
164 #define ADD_LINE_S(t, n, v) \
165 	do {							\
166 		if (cur >= dispstart && cur < end) { 		\
167 			print_fld_str(FLD_PF_TYPE, (t));	\
168 			print_fld_str(FLD_PF_NAME, (n));	\
169 			print_fld_str(FLD_PF_VALUE, (v));	\
170 			end_line();				\
171 		}						\
172 		if (++cur >= end)				\
173 			return;					\
174 	} while (0)
175 
176 #define ADD_LINE_V(t, n, v) \
177 	do {							\
178 		if (cur >= dispstart && cur < end) { 		\
179 			print_fld_str(FLD_PF_TYPE, (t));	\
180 			print_fld_str(FLD_PF_NAME, (n));	\
181 			print_fld_size(FLD_PF_VALUE, (v));	\
182 			end_line();				\
183 		}						\
184 		if (++cur >= end)				\
185 			return;					\
186 	} while (0)
187 
188 #define ADD_LINE_VR(t, n, v, r) \
189 	do {							\
190 		if (cur >= dispstart && cur < end) { 		\
191 			print_fld_str(FLD_PF_TYPE, (t));	\
192 			print_fld_str(FLD_PF_NAME, (n));	\
193 			print_fld_size(FLD_PF_VALUE, (v));	\
194 			print_fld_double(FLD_PF_RATE, (r));	\
195 			end_line();				\
196 		}						\
197 		if (++cur >= end)				\
198 			return;					\
199 	} while (0)
200 
201 
202 void
203 print_pf(void)
204 {
205 	char		*debug;
206 	time_t		tm = 0;
207 	struct timespec	uptime;
208 	int		i;
209 	struct pf_status *s = &status;
210 
211 	int cur = 0;
212 	int end = dispstart + maxprint;
213 	if (end > num_disp)
214 		end = num_disp;
215 
216 	if (!clock_gettime(CLOCK_BOOTTIME, &uptime))
217 		tm = uptime.tv_sec - s->since;
218 
219 	ADD_LINE_S("pf", "Status", s->running ? "Enabled" : "Disabled");
220 	ADD_LINE_A("pf", "Since", tm);
221 
222 	switch (s->debug) {
223 	case LOG_EMERG:
224 		debug = "emerg";
225 		break;
226 	case LOG_ALERT:
227 		debug = "alert";
228 		break;
229 	case LOG_CRIT:
230 		debug = "crit";
231 		break;
232 	case LOG_ERR:
233 		debug = "err";
234 		break;
235 	case LOG_WARNING:
236 		debug = "warning";
237 		break;
238 	case LOG_NOTICE:
239 		debug = "notice";
240 		break;
241 	case LOG_INFO:
242 		debug = "info";
243 		break;
244 	case LOG_DEBUG:
245 		debug = "debug";
246 		break;
247 	default:
248 		debug = "unknown";
249 		break;
250 	}
251 	ADD_LINE_S("pf", "Debug", debug);
252 
253 	tb_start();
254 	tbprintf("0x%08x\n", ntohl(s->hostid));
255 	tb_end();
256 
257 	ADD_LINE_S("pf", "Hostid", tmp_buf);
258 
259 	if (s->ifname[0] != 0) {
260 		ADD_EMPTY_LINE;
261 		ADD_LINE_V(s->ifname, "Bytes In IPv4", s->bcounters[0][0]);
262 		ADD_LINE_V(s->ifname, "Bytes In IPv6", s->bcounters[1][0]);
263 		ADD_LINE_V(s->ifname, "Bytes Out IPv4", s->bcounters[0][1]);
264 		ADD_LINE_V(s->ifname, "Bytes Out IPv6", s->bcounters[1][1]);
265 		ADD_LINE_V(s->ifname, "Packets In Passed IPv4", s->pcounters[0][0][PF_PASS]);
266 		ADD_LINE_V(s->ifname, "Packets In Passed IPv6", s->pcounters[1][0][PF_PASS]);
267 		ADD_LINE_V(s->ifname, "Packets In Blocked IPv4", s->pcounters[0][0][PF_DROP]);
268 		ADD_LINE_V(s->ifname, "Packets In Blocked IPv6", s->pcounters[1][0][PF_DROP]);
269 		ADD_LINE_V(s->ifname, "Packets Out Passed IPv4", s->pcounters[0][1][PF_PASS]);
270 		ADD_LINE_V(s->ifname, "Packets Out Passed IPv6", s->pcounters[1][1][PF_PASS]);
271 		ADD_LINE_V(s->ifname, "Packets Out Blocked IPv4", s->pcounters[0][1][PF_DROP]);
272 		ADD_LINE_V(s->ifname, "Packets Out Blocked IPv6", s->pcounters[1][1][PF_DROP]);
273 	}
274 
275 
276 	ADD_EMPTY_LINE;
277 	ADD_LINE_V("state", "Count", s->states);
278 
279 	for (i = 0; i < FCNT_MAX; i++) {
280 		if (tm > 0)
281 			ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i],
282 				    (double)s->fcounters[i] / (double)tm);
283 		else
284 			ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]);
285 	}
286 
287 
288 	ADD_EMPTY_LINE;
289 	ADD_LINE_V("src track", "Count", s->src_nodes);
290 
291 	for (i = 0; i < SCNT_MAX; i++) {
292 		if (tm > 0)
293 			ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i],
294 				    (double)s->scounters[i] / (double)tm);
295 		else
296 			ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]);
297 	}
298 
299 	ADD_EMPTY_LINE;
300 	for (i = 0; i < PFRES_MAX; i++) {
301 		if (tm > 0)
302 			ADD_LINE_VR("counter", pf_reasons[i], s->counters[i],
303 				    (double)s->counters[i] / (double)tm);
304 		else
305 			ADD_LINE_V("counter", pf_reasons[i], s->counters[i]);
306 	}
307 
308 	ADD_EMPTY_LINE;
309 	for (i = 0; i < LCNT_MAX; i++) {
310 		if (tm > 0)
311 			ADD_LINE_VR("limit counter", pf_lcounters[i], s->lcounters[i],
312 				    (double)s->lcounters[i] / (double)tm);
313 		else
314 			ADD_LINE_V("limit counter", pf_lcounters[i], s->lcounters[i]);
315 	}
316 }
317