1 /* $OpenBSD: pf.c,v 1.1 2008/06/12 22:26:01 canacar 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 <sys/proc.h> 23 #include <net/if.h> 24 #include <netinet/in.h> 25 #include <netinet/in_systm.h> 26 #include <netinet/ip.h> 27 #include <netinet/ip_icmp.h> 28 #include <netinet/icmp6.h> 29 #include <net/pfvar.h> 30 #include <arpa/inet.h> 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <ctype.h> 36 #include <netdb.h> 37 #include <stdarg.h> 38 #include <errno.h> 39 #include <err.h> 40 #include <ifaddrs.h> 41 #include <unistd.h> 42 #include <net/pfvar.h> 43 #include "pfctl_parser.h" 44 #include "engine.h" 45 #include "systat.h" 46 47 void print_pf(void); 48 int read_pf(void); 49 int select_pf(void); 50 51 const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; 52 const char *pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; 53 const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; 54 const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; 55 56 static struct pf_status status; 57 extern int pf_dev; 58 int num_pf = 0; 59 60 field_def fields_pf[] = { 61 {"TYPE", 13, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 62 {"NAME", 12, 24, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 63 {"VALUE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 64 {"RATE", 8, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 60}, 65 {"NOTES", 10, 20, 1, FLD_ALIGN_LEFT, -1, 0, 0, 60}, 66 }; 67 68 #define FIELD_ADDR(x) (&fields_pf[x]) 69 70 #define FLD_PF_TYPE FIELD_ADDR(0) 71 #define FLD_PF_NAME FIELD_ADDR(1) 72 #define FLD_PF_VALUE FIELD_ADDR(2) 73 #define FLD_PF_RATE FIELD_ADDR(3) 74 #define FLD_PF_DESC FIELD_ADDR(4) 75 76 /* Define views */ 77 field_def *view_pf_0[] = { 78 FLD_PF_TYPE, FLD_PF_NAME, FLD_PF_VALUE, FLD_PF_RATE, FLD_PF_DESC, NULL 79 }; 80 81 82 /* Define view managers */ 83 struct view_manager pf_mgr = { 84 "PF", select_pf, read_pf, NULL, print_header, 85 print_pf, keyboard_callback, NULL, NULL 86 }; 87 88 field_view views_pf[] = { 89 {view_pf_0, "pf", 'P', &pf_mgr}, 90 {NULL, NULL, 0, NULL} 91 }; 92 93 94 95 int 96 select_pf(void) 97 { 98 return (0); 99 } 100 101 int 102 read_pf(void) 103 { 104 if (pf_dev < 0) { 105 num_disp = 0; 106 return 0; 107 } 108 109 if (ioctl(pf_dev, DIOCGETSTATUS, &status)) { 110 error("DIOCGETSTATUS: %s", strerror(errno)); 111 return (-1); 112 } 113 114 num_disp = 4; 115 116 if (status.ifname[0] != 0) 117 num_disp += 13; 118 119 num_disp += FCNT_MAX + 2; 120 num_disp += SCNT_MAX + 2; 121 num_disp += PFRES_MAX + 1; 122 num_disp += LCNT_MAX + 1; 123 124 return (0); 125 } 126 127 int 128 initpf(void) 129 { 130 field_view *v; 131 132 for (v = views_pf; v->name != NULL; v++) 133 add_view(v); 134 135 return(1); 136 } 137 138 void 139 print_fld_double(field_def *fld, double val) 140 { 141 int len; 142 143 if (fld == NULL) 144 return; 145 146 len = fld->width; 147 if (len < 1) 148 return; 149 150 tb_start(); 151 if (tbprintf("%.2f", val) > len) 152 print_fld_str(fld, "*"); 153 else 154 print_fld_tb(fld); 155 tb_end(); 156 } 157 158 #define ADD_LINE_A(t, n, v) \ 159 do { \ 160 if (cur >= dispstart && cur < end) { \ 161 print_fld_str(FLD_PF_TYPE, (t)); \ 162 print_fld_str(FLD_PF_NAME, (n)); \ 163 print_fld_age(FLD_PF_VALUE, (v)); \ 164 end_line(); \ 165 } \ 166 if (++cur >= end) \ 167 return; \ 168 } while (0) 169 170 #define ADD_EMPTY_LINE \ 171 do { \ 172 if (cur >= dispstart && cur < end) \ 173 end_line(); \ 174 if (++cur >= end) \ 175 return; \ 176 } while (0) 177 178 #define ADD_LINE_S(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_str(FLD_PF_VALUE, (v)); \ 184 end_line(); \ 185 } \ 186 if (++cur >= end) \ 187 return; \ 188 } while (0) 189 190 #define ADD_LINE_V(t, n, v) \ 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 end_line(); \ 197 } \ 198 if (++cur >= end) \ 199 return; \ 200 } while (0) 201 202 #define ADD_LINE_VD(t, n, v, d) \ 203 do { \ 204 if (cur >= dispstart && cur < end) { \ 205 print_fld_str(FLD_PF_TYPE, (t)); \ 206 print_fld_str(FLD_PF_NAME, (n)); \ 207 print_fld_size(FLD_PF_VALUE, (v)); \ 208 print_fld_str(FLD_PF_DESC, (d)); \ 209 end_line(); \ 210 } \ 211 if (++cur >= end) \ 212 return; \ 213 } while (0) 214 215 #define ADD_LINE_VR(t, n, v, r) \ 216 do { \ 217 if (cur >= dispstart && cur < end) { \ 218 print_fld_str(FLD_PF_TYPE, (t)); \ 219 print_fld_str(FLD_PF_NAME, (n)); \ 220 print_fld_size(FLD_PF_VALUE, (v)); \ 221 print_fld_double(FLD_PF_RATE, (r)); \ 222 end_line(); \ 223 } \ 224 if (++cur >= end) \ 225 return; \ 226 } while (0) 227 228 229 void 230 print_pf(void) 231 { 232 char *debug; 233 time_t tm; 234 int i; 235 struct pf_status *s = &status; 236 237 int cur = 0; 238 int end = dispstart + maxprint; 239 if (end > num_disp) 240 end = num_disp; 241 242 tm = time(NULL) - s->since; 243 244 ADD_LINE_S("pf", "Status", s->running ? "Enabled" : "Disabled"); 245 ADD_LINE_A("pf", "Since", tm); 246 247 switch (s->debug) { 248 case PF_DEBUG_NONE: 249 debug = "None"; 250 break; 251 case PF_DEBUG_URGENT: 252 debug = "Urgent"; 253 break; 254 case PF_DEBUG_MISC: 255 debug = "Misc"; 256 break; 257 case PF_DEBUG_NOISY: 258 debug = "Loud"; 259 break; 260 } 261 ADD_LINE_S("pf", "Debug", debug); 262 263 tb_start(); 264 tbprintf("0x%08x\n", ntohl(s->hostid)); 265 tb_end(); 266 267 ADD_LINE_S("pf", "Hostid", tmp_buf); 268 269 if (s->ifname[0] != 0) { 270 ADD_EMPTY_LINE; 271 ADD_LINE_VD(s->ifname, "Bytes In", s->bcounters[0][0], "IPv4"); 272 ADD_LINE_VD(s->ifname, "Bytes In", s->bcounters[1][0], "IPv6"); 273 ADD_LINE_VD(s->ifname, "Bytes Out", s->bcounters[0][1], "IPv4"); 274 ADD_LINE_VD(s->ifname, "Bytes Out", s->bcounters[1][1], "IPv6"); 275 ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[0][0][PF_PASS], "IPv4, Passed"); 276 ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[1][0][PF_PASS], "IPv6, Passed"); 277 ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[0][0][PF_DROP], "IPv4, Blocked"); 278 ADD_LINE_VD(s->ifname, "Packets In", s->pcounters[1][0][PF_DROP], "IPv6, Blocked"); 279 ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[0][1][PF_PASS], "IPv4, Passed"); 280 ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[1][1][PF_PASS], "IPv6, Passed"); 281 ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[0][1][PF_DROP], "IPv4, Blocked"); 282 ADD_LINE_VD(s->ifname, "Packets Out", s->pcounters[1][1][PF_DROP], "IPv6, Blocked"); 283 } 284 285 286 ADD_EMPTY_LINE; 287 ADD_LINE_V("state", "Count", s->states); 288 289 for (i = 0; i < FCNT_MAX; i++) { 290 if (tm > 0) 291 ADD_LINE_VR("state", pf_fcounters[i], s->fcounters[i], 292 (double)s->fcounters[i] / (double)tm); 293 else 294 ADD_LINE_V("state", pf_fcounters[i], s->fcounters[i]); 295 } 296 297 298 ADD_EMPTY_LINE; 299 ADD_LINE_V("src track", "Count", s->src_nodes); 300 301 for (i = 0; i < SCNT_MAX; i++) { 302 if (tm > 0) 303 ADD_LINE_VR("src track", pf_scounters[i], s->scounters[i], 304 (double)s->scounters[i] / (double)tm); 305 else 306 ADD_LINE_V("src track", pf_scounters[i], s->scounters[i]); 307 } 308 309 ADD_EMPTY_LINE; 310 for (i = 0; i < PFRES_MAX; i++) { 311 if (tm > 0) 312 ADD_LINE_VR("counter", pf_reasons[i], s->counters[i], 313 (double)s->counters[i] / (double)tm); 314 else 315 ADD_LINE_V("counter", pf_reasons[i], s->counters[i]); 316 } 317 318 ADD_EMPTY_LINE; 319 for (i = 0; i < LCNT_MAX; i++) { 320 if (tm > 0) 321 ADD_LINE_VR("limit counter", pf_lcounters[i], s->lcounters[i], 322 (double)s->lcounters[i] / (double)tm); 323 else 324 ADD_LINE_V("limit counter", pf_lcounters[i], s->lcounters[i]); 325 } 326 } 327