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 85 select_pf(void) 86 { 87 return (0); 88 } 89 90 int 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 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_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 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