1 /* $OpenBSD: pf.c,v 1.5 2012/12/04 02:24:47 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/ioctl.h> 20 #include <sys/socket.h> 21 #include <net/if.h> 22 #include <netinet/in.h> 23 #include <netinet/in_systm.h> 24 #include <netinet/ip.h> 25 #include <net/pfvar.h> 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <ctype.h> 31 #include <errno.h> 32 #include <err.h> 33 #include <unistd.h> 34 #include <syslog.h> 35 #include "pfctl_parser.h" 36 #include "systat.h" 37 38 void print_pf(void); 39 int read_pf(void); 40 int select_pf(void); 41 void print_fld_double(field_def *, double); 42 43 const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; 44 const char *pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; 45 const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; 46 const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; 47 48 static struct pf_status status; 49 extern int pf_dev; 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 if (pf_dev < 0) { 95 num_disp = 0; 96 return 0; 97 } 98 99 if (ioctl(pf_dev, DIOCGETSTATUS, &status)) { 100 error("DIOCGETSTATUS: %s", strerror(errno)); 101 return (-1); 102 } 103 104 num_disp = 4; 105 106 if (status.ifname[0] != 0) 107 num_disp += 13; 108 109 num_disp += FCNT_MAX + 2; 110 num_disp += SCNT_MAX + 2; 111 num_disp += PFRES_MAX + 1; 112 num_disp += LCNT_MAX + 1; 113 114 return (0); 115 } 116 117 int 118 initpf(void) 119 { 120 field_view *v; 121 122 for (v = views_pf; v->name != NULL; v++) 123 add_view(v); 124 125 return(1); 126 } 127 128 void 129 print_fld_double(field_def *fld, double val) 130 { 131 int len; 132 133 if (fld == NULL) 134 return; 135 136 len = fld->width; 137 if (len < 1) 138 return; 139 140 tb_start(); 141 if (tbprintf("%.2f", val) > len) 142 print_fld_str(fld, "*"); 143 else 144 print_fld_tb(fld); 145 tb_end(); 146 } 147 148 #define ADD_LINE_A(t, n, v) \ 149 do { \ 150 if (cur >= dispstart && cur < end) { \ 151 print_fld_str(FLD_PF_TYPE, (t)); \ 152 print_fld_str(FLD_PF_NAME, (n)); \ 153 print_fld_age(FLD_PF_VALUE, (v)); \ 154 end_line(); \ 155 } \ 156 if (++cur >= end) \ 157 return; \ 158 } while (0) 159 160 #define ADD_EMPTY_LINE \ 161 do { \ 162 if (cur >= dispstart && cur < end) \ 163 end_line(); \ 164 if (++cur >= end) \ 165 return; \ 166 } while (0) 167 168 #define ADD_LINE_S(t, n, v) \ 169 do { \ 170 if (cur >= dispstart && cur < end) { \ 171 print_fld_str(FLD_PF_TYPE, (t)); \ 172 print_fld_str(FLD_PF_NAME, (n)); \ 173 print_fld_str(FLD_PF_VALUE, (v)); \ 174 end_line(); \ 175 } \ 176 if (++cur >= end) \ 177 return; \ 178 } while (0) 179 180 #define ADD_LINE_V(t, n, v) \ 181 do { \ 182 if (cur >= dispstart && cur < end) { \ 183 print_fld_str(FLD_PF_TYPE, (t)); \ 184 print_fld_str(FLD_PF_NAME, (n)); \ 185 print_fld_size(FLD_PF_VALUE, (v)); \ 186 end_line(); \ 187 } \ 188 if (++cur >= end) \ 189 return; \ 190 } while (0) 191 192 #define ADD_LINE_VD(t, n, v, d) \ 193 do { \ 194 if (cur >= dispstart && cur < end) { \ 195 print_fld_str(FLD_PF_TYPE, (t)); \ 196 print_fld_str(FLD_PF_NAME, (n)); \ 197 print_fld_size(FLD_PF_VALUE, (v)); \ 198 print_fld_str(FLD_PF_DESC, (d)); \ 199 end_line(); \ 200 } \ 201 if (++cur >= end) \ 202 return; \ 203 } while (0) 204 205 #define ADD_LINE_VR(t, n, v, r) \ 206 do { \ 207 if (cur >= dispstart && cur < end) { \ 208 print_fld_str(FLD_PF_TYPE, (t)); \ 209 print_fld_str(FLD_PF_NAME, (n)); \ 210 print_fld_size(FLD_PF_VALUE, (v)); \ 211 print_fld_double(FLD_PF_RATE, (r)); \ 212 end_line(); \ 213 } \ 214 if (++cur >= end) \ 215 return; \ 216 } while (0) 217 218 219 void 220 print_pf(void) 221 { 222 char *debug; 223 time_t tm; 224 int i; 225 struct pf_status *s = &status; 226 227 int cur = 0; 228 int end = dispstart + maxprint; 229 if (end > num_disp) 230 end = num_disp; 231 232 tm = time(NULL) - 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 } 263 ADD_LINE_S("pf", "Debug", debug); 264 265 tb_start(); 266 tbprintf("0x%08x\n", ntohl(s->hostid)); 267 tb_end(); 268 269 ADD_LINE_S("pf", "Hostid", tmp_buf); 270 271 if (s->ifname[0] != 0) { 272 ADD_EMPTY_LINE; 273 ADD_LINE_VD(s->ifname, "Bytes In", s->bcounters[0][0], "IPv4"); 274 ADD_LINE_VD(s->ifname, "Bytes In", s->bcounters[1][0], "IPv6"); 275 ADD_LINE_VD(s->ifname, "Bytes Out", s->bcounters[0][1], "IPv4"); 276 ADD_LINE_VD(s->ifname, "Bytes Out", s->bcounters[1][1], "IPv6"); 277 ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[0][0][PF_PASS], "IPv4, Passed"); 278 ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[1][0][PF_PASS], "IPv6, Passed"); 279 ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[0][0][PF_DROP], "IPv4, Blocked"); 280 ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[1][0][PF_DROP], "IPv6, Blocked"); 281 ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[0][1][PF_PASS], "IPv4, Passed"); 282 ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[1][1][PF_PASS], "IPv6, Passed"); 283 ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[0][1][PF_DROP], "IPv4, Blocked"); 284 ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[1][1][PF_DROP], "IPv6, Blocked"); 285 } 286 287 288 ADD_EMPTY_LINE; 289 ADD_LINE_V("state", "Count", s->states); 290 291 for (i = 0; i < FCNT_MAX; i++) { 292 if (tm > 0) 293 ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i], 294 (double)s->fcounters[i] / (double)tm); 295 else 296 ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]); 297 } 298 299 300 ADD_EMPTY_LINE; 301 ADD_LINE_V("src track", "Count", s->src_nodes); 302 303 for (i = 0; i < SCNT_MAX; i++) { 304 if (tm > 0) 305 ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i], 306 (double)s->scounters[i] / (double)tm); 307 else 308 ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]); 309 } 310 311 ADD_EMPTY_LINE; 312 for (i = 0; i < PFRES_MAX; i++) { 313 if (tm > 0) 314 ADD_LINE_VR("counter", pf_reasons[i], s->counters[i], 315 (double)s->counters[i] / (double)tm); 316 else 317 ADD_LINE_V("counter", pf_reasons[i], s->counters[i]); 318 } 319 320 ADD_EMPTY_LINE; 321 for (i = 0; i < LCNT_MAX; i++) { 322 if (tm > 0) 323 ADD_LINE_VR("limit counter", pf_lcounters[i], s->lcounters[i], 324 (double)s->lcounters[i] / (double)tm); 325 else 326 ADD_LINE_V("limit counter", pf_lcounters[i], s->lcounters[i]); 327 } 328 } 329