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