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