1 /* $OpenBSD: pf.c,v 1.14 2024/04/22 13:30:22 bluhm 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[SCNT_MAX+1] = FCNT_NAMES;
48 const char *pf_ncounters[NCNT_MAX+1] = FCNT_NAMES;
49
50 static struct pf_status status;
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 };
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
65 /* Define views */
66 field_def *view_pf_0[] = {
67 FLD_PF_TYPE, FLD_PF_NAME, FLD_PF_VALUE, FLD_PF_RATE, NULL
68 };
69
70
71 /* Define view managers */
72 struct view_manager pf_mgr = {
73 "PF", select_pf, read_pf, NULL, print_header,
74 print_pf, keyboard_callback, NULL, NULL
75 };
76
77 field_view views_pf[] = {
78 {view_pf_0, "pf", 'P', &pf_mgr},
79 {NULL, NULL, 0, NULL}
80 };
81
82
83
84 int
select_pf(void)85 select_pf(void)
86 {
87 return (0);
88 }
89
90 int
read_pf(void)91 read_pf(void)
92 {
93 size_t size = sizeof(status);
94 int mib[3] = { CTL_KERN, KERN_PFSTATUS };
95
96 if (sysctl(mib, 2, &status, &size, NULL, 0) == -1) {
97 error("sysctl(PFCTL_STATUS): %s", strerror(errno));
98 return (-1);
99 }
100
101 num_disp = 4;
102
103 if (status.ifname[0] != 0)
104 num_disp += 13;
105
106 num_disp += FCNT_MAX + 2;
107 num_disp += SCNT_MAX + 2;
108 num_disp += NCNT_MAX + 2;
109 num_disp += PFRES_MAX + 1;
110 num_disp += LCNT_MAX + 1;
111
112 return (0);
113 }
114
115 int
initpf(void)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
print_fld_double(field_def * fld,double val)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_VR(t, n, v, r) \
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_double(FLD_PF_RATE, (r)); \
197 end_line(); \
198 } \
199 if (++cur >= end) \
200 return; \
201 } while (0)
202
203
204 void
print_pf(void)205 print_pf(void)
206 {
207 char *debug;
208 time_t tm = 0;
209 struct timespec uptime;
210 int i;
211 struct pf_status *s = &status;
212
213 int cur = 0;
214 int end = dispstart + maxprint;
215 if (end > num_disp)
216 end = num_disp;
217
218 if (!clock_gettime(CLOCK_BOOTTIME, &uptime))
219 tm = uptime.tv_sec - s->since;
220
221 ADD_LINE_S("pf", "Status", s->running ? "Enabled" : "Disabled");
222 ADD_LINE_A("pf", "Since", tm);
223
224 switch (s->debug) {
225 case LOG_EMERG:
226 debug = "emerg";
227 break;
228 case LOG_ALERT:
229 debug = "alert";
230 break;
231 case LOG_CRIT:
232 debug = "crit";
233 break;
234 case LOG_ERR:
235 debug = "err";
236 break;
237 case LOG_WARNING:
238 debug = "warning";
239 break;
240 case LOG_NOTICE:
241 debug = "notice";
242 break;
243 case LOG_INFO:
244 debug = "info";
245 break;
246 case LOG_DEBUG:
247 debug = "debug";
248 break;
249 default:
250 debug = "unknown";
251 break;
252 }
253 ADD_LINE_S("pf", "Debug", debug);
254
255 tb_start();
256 tbprintf("0x%08x\n", ntohl(s->hostid));
257 tb_end();
258
259 ADD_LINE_S("pf", "Hostid", tmp_buf);
260
261 if (s->ifname[0] != 0) {
262 ADD_EMPTY_LINE;
263 ADD_LINE_V(s->ifname, "Bytes In IPv4", s->bcounters[0][0]);
264 ADD_LINE_V(s->ifname, "Bytes In IPv6", s->bcounters[1][0]);
265 ADD_LINE_V(s->ifname, "Bytes Out IPv4", s->bcounters[0][1]);
266 ADD_LINE_V(s->ifname, "Bytes Out IPv6", s->bcounters[1][1]);
267 ADD_LINE_V(s->ifname, "Packets In Passed IPv4", s->pcounters[0][0][PF_PASS]);
268 ADD_LINE_V(s->ifname, "Packets In Passed IPv6", s->pcounters[1][0][PF_PASS]);
269 ADD_LINE_V(s->ifname, "Packets In Blocked IPv4", s->pcounters[0][0][PF_DROP]);
270 ADD_LINE_V(s->ifname, "Packets In Blocked IPv6", s->pcounters[1][0][PF_DROP]);
271 ADD_LINE_V(s->ifname, "Packets Out Passed IPv4", s->pcounters[0][1][PF_PASS]);
272 ADD_LINE_V(s->ifname, "Packets Out Passed IPv6", s->pcounters[1][1][PF_PASS]);
273 ADD_LINE_V(s->ifname, "Packets Out Blocked IPv4", s->pcounters[0][1][PF_DROP]);
274 ADD_LINE_V(s->ifname, "Packets Out Blocked IPv6", s->pcounters[1][1][PF_DROP]);
275 }
276
277
278 ADD_EMPTY_LINE;
279 ADD_LINE_V("state", "Count", s->states);
280
281 for (i = 0; i < FCNT_MAX; i++) {
282 if (tm > 0)
283 ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i],
284 (double)s->fcounters[i] / (double)tm);
285 else
286 ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]);
287 }
288
289
290 ADD_EMPTY_LINE;
291 ADD_LINE_V("src track", "Count", s->src_nodes);
292
293 for (i = 0; i < SCNT_MAX; i++) {
294 if (tm > 0)
295 ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i],
296 (double)s->scounters[i] / (double)tm);
297 else
298 ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]);
299 }
300
301 ADD_EMPTY_LINE;
302 ADD_LINE_V("fragment", "Count", s->fragments);
303
304 for (i = 0; i < NCNT_MAX; i++) {
305 if (tm > 0)
306 ADD_LINE_VR("fragment", pf_ncounters[i], s->ncounters[i],
307 (double)s->ncounters[i] / (double)tm);
308 else
309 ADD_LINE_V("fragment", pf_ncounters[i], s->ncounters[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