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