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