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