xref: /openbsd-src/usr.bin/systat/pf.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: pf.c,v 1.11 2019/06/28 13:35:04 deraadt 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 	{"NOTES", 10, 20, 1, FLD_ALIGN_LEFT, -1, 0, 0, 60},
58 };
59 
60 #define FLD_PF_TYPE	FIELD_ADDR(fields_pf,0)
61 #define FLD_PF_NAME	FIELD_ADDR(fields_pf,1)
62 #define FLD_PF_VALUE	FIELD_ADDR(fields_pf,2)
63 #define FLD_PF_RATE	FIELD_ADDR(fields_pf,3)
64 #define FLD_PF_DESC	FIELD_ADDR(fields_pf,4)
65 
66 /* Define views */
67 field_def *view_pf_0[] = {
68 	FLD_PF_TYPE, FLD_PF_NAME, FLD_PF_VALUE, FLD_PF_RATE, FLD_PF_DESC, NULL
69 };
70 
71 
72 /* Define view managers */
73 struct view_manager pf_mgr = {
74 	"PF", select_pf, read_pf, NULL, print_header,
75 	print_pf, keyboard_callback, NULL, NULL
76 };
77 
78 field_view views_pf[] = {
79 	{view_pf_0, "pf", 'P', &pf_mgr},
80 	{NULL, NULL, 0, NULL}
81 };
82 
83 
84 
85 int
86 select_pf(void)
87 {
88 	return (0);
89 }
90 
91 int
92 read_pf(void)
93 {
94 	size_t size = sizeof(status);
95 	int mib[3] = { CTL_KERN, KERN_PFSTATUS };
96 
97 	if (sysctl(mib, 2, &status, &size, NULL, 0) == -1) {
98 		error("sysctl(PFCTL_STATUS): %s", strerror(errno));
99 		return (-1);
100 	}
101 
102 	num_disp = 4;
103 
104 	if (status.ifname[0] != 0)
105 		num_disp += 13;
106 
107 	num_disp += FCNT_MAX + 2;
108 	num_disp += SCNT_MAX + 2;
109 	num_disp += PFRES_MAX + 1;
110 	num_disp += LCNT_MAX + 1;
111 
112 	return (0);
113 }
114 
115 int
116 initpf(void)
117 {
118 	field_view *v;
119 
120 	for (v = views_pf; v->name != NULL; v++)
121 		add_view(v);
122 
123 	return(1);
124 }
125 
126 void
127 print_fld_double(field_def *fld, double val)
128 {
129 	int len;
130 
131 	if (fld == NULL)
132 		return;
133 
134 	len = fld->width;
135 	if (len < 1)
136 		return;
137 
138 	tb_start();
139 	if (tbprintf("%.2f", val) > len)
140 		print_fld_str(fld, "*");
141 	else
142 		print_fld_tb(fld);
143 	tb_end();
144 }
145 
146 #define ADD_LINE_A(t, n, v) \
147 	do {							\
148 		if (cur >= dispstart && cur < end) { 		\
149 			print_fld_str(FLD_PF_TYPE, (t));	\
150 			print_fld_str(FLD_PF_NAME, (n));	\
151 			print_fld_age(FLD_PF_VALUE, (v));	\
152 			end_line();				\
153 		}						\
154 		if (++cur >= end)				\
155 			return;					\
156 	} while (0)
157 
158 #define ADD_EMPTY_LINE \
159 	do {							\
160 		if (cur >= dispstart && cur < end) 		\
161 			end_line();				\
162 		if (++cur >= end)				\
163 			return;					\
164 	} while (0)
165 
166 #define ADD_LINE_S(t, n, v) \
167 	do {							\
168 		if (cur >= dispstart && cur < end) { 		\
169 			print_fld_str(FLD_PF_TYPE, (t));	\
170 			print_fld_str(FLD_PF_NAME, (n));	\
171 			print_fld_str(FLD_PF_VALUE, (v));	\
172 			end_line();				\
173 		}						\
174 		if (++cur >= end)				\
175 			return;					\
176 	} while (0)
177 
178 #define ADD_LINE_V(t, n, v) \
179 	do {							\
180 		if (cur >= dispstart && cur < end) { 		\
181 			print_fld_str(FLD_PF_TYPE, (t));	\
182 			print_fld_str(FLD_PF_NAME, (n));	\
183 			print_fld_size(FLD_PF_VALUE, (v));	\
184 			end_line();				\
185 		}						\
186 		if (++cur >= end)				\
187 			return;					\
188 	} while (0)
189 
190 #define ADD_LINE_VD(t, n, v, d) \
191 	do {							\
192 		if (cur >= dispstart && cur < end) { 		\
193 			print_fld_str(FLD_PF_TYPE, (t));	\
194 			print_fld_str(FLD_PF_NAME, (n));	\
195 			print_fld_size(FLD_PF_VALUE, (v));	\
196 			print_fld_str(FLD_PF_DESC, (d));	\
197 			end_line();				\
198 		}						\
199 		if (++cur >= end)				\
200 			return;					\
201 	} while (0)
202 
203 #define ADD_LINE_VR(t, n, v, r) \
204 	do {							\
205 		if (cur >= dispstart && cur < end) { 		\
206 			print_fld_str(FLD_PF_TYPE, (t));	\
207 			print_fld_str(FLD_PF_NAME, (n));	\
208 			print_fld_size(FLD_PF_VALUE, (v));	\
209 			print_fld_double(FLD_PF_RATE, (r));	\
210 			end_line();				\
211 		}						\
212 		if (++cur >= end)				\
213 			return;					\
214 	} while (0)
215 
216 
217 void
218 print_pf(void)
219 {
220 	char		*debug;
221 	time_t		tm = 0;
222 	struct timespec	uptime;
223 	int		i;
224 	struct pf_status *s = &status;
225 
226 	int cur = 0;
227 	int end = dispstart + maxprint;
228 	if (end > num_disp)
229 		end = num_disp;
230 
231 	if (!clock_gettime(CLOCK_UPTIME, &uptime))
232 		tm = uptime.tv_sec - s->since;
233 
234 	ADD_LINE_S("pf", "Status", s->running ? "Enabled" : "Disabled");
235 	ADD_LINE_A("pf", "Since", tm);
236 
237 	switch (s->debug) {
238 	case LOG_EMERG:
239 		debug = "emerg";
240 		break;
241 	case LOG_ALERT:
242 		debug = "alert";
243 		break;
244 	case LOG_CRIT:
245 		debug = "crit";
246 		break;
247 	case LOG_ERR:
248 		debug = "err";
249 		break;
250 	case LOG_WARNING:
251 		debug = "warning";
252 		break;
253 	case LOG_NOTICE:
254 		debug = "notice";
255 		break;
256 	case LOG_INFO:
257 		debug = "info";
258 		break;
259 	case LOG_DEBUG:
260 		debug = "debug";
261 		break;
262 	default:
263 		debug = "unknown";
264 		break;
265 	}
266 	ADD_LINE_S("pf", "Debug", debug);
267 
268 	tb_start();
269 	tbprintf("0x%08x\n", ntohl(s->hostid));
270 	tb_end();
271 
272 	ADD_LINE_S("pf", "Hostid", tmp_buf);
273 
274 	if (s->ifname[0] != 0) {
275 		ADD_EMPTY_LINE;
276 		ADD_LINE_VD(s->ifname, "Bytes In", s->bcounters[0][0], "IPv4");
277 		ADD_LINE_VD(s->ifname, "Bytes In", s->bcounters[1][0], "IPv6");
278 		ADD_LINE_VD(s->ifname, "Bytes Out", s->bcounters[0][1], "IPv4");
279 		ADD_LINE_VD(s->ifname, "Bytes Out", s->bcounters[1][1], "IPv6");
280 		ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[0][0][PF_PASS], "IPv4, Passed");
281 		ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[1][0][PF_PASS], "IPv6, Passed");
282 		ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[0][0][PF_DROP], "IPv4, Blocked");
283 		ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[1][0][PF_DROP], "IPv6, Blocked");
284 		ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[0][1][PF_PASS], "IPv4, Passed");
285 		ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[1][1][PF_PASS], "IPv6, Passed");
286 		ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[0][1][PF_DROP], "IPv4, Blocked");
287 		ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[1][1][PF_DROP], "IPv6, Blocked");
288 	}
289 
290 
291 	ADD_EMPTY_LINE;
292 	ADD_LINE_V("state", "Count", s->states);
293 
294 	for (i = 0; i < FCNT_MAX; i++) {
295 		if (tm > 0)
296 			ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i],
297 				    (double)s->fcounters[i] / (double)tm);
298 		else
299 			ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]);
300 	}
301 
302 
303 	ADD_EMPTY_LINE;
304 	ADD_LINE_V("src track", "Count", s->src_nodes);
305 
306 	for (i = 0; i < SCNT_MAX; i++) {
307 		if (tm > 0)
308 			ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i],
309 				    (double)s->scounters[i] / (double)tm);
310 		else
311 			ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]);
312 	}
313 
314 	ADD_EMPTY_LINE;
315 	for (i = 0; i < PFRES_MAX; i++) {
316 		if (tm > 0)
317 			ADD_LINE_VR("counter", pf_reasons[i], s->counters[i],
318 				    (double)s->counters[i] / (double)tm);
319 		else
320 			ADD_LINE_V("counter", pf_reasons[i], s->counters[i]);
321 	}
322 
323 	ADD_EMPTY_LINE;
324 	for (i = 0; i < LCNT_MAX; i++) {
325 		if (tm > 0)
326 			ADD_LINE_VR("limit counter", pf_lcounters[i], s->lcounters[i],
327 				    (double)s->lcounters[i] / (double)tm);
328 		else
329 			ADD_LINE_V("limit counter", pf_lcounters[i], s->lcounters[i]);
330 	}
331 }
332