1 /* $OpenBSD: pftop.c,v 1.34 2016/04/13 05:25:45 jasper Exp $ */ 2 /* 3 * Copyright (c) 2001, 2007 Can Erkin Acar 4 * Copyright (c) 2001 Daniel Hartmeier 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 #include <sys/types.h> 34 #include <sys/ioctl.h> 35 #include <sys/socket.h> 36 37 #include <net/if.h> 38 #include <netinet/in.h> 39 #include <netinet/tcp.h> 40 #include <netinet/tcp_fsm.h> 41 #include <net/pfvar.h> 42 #include <arpa/inet.h> 43 44 #include <net/hfsc.h> 45 46 #include <ctype.h> 47 #include <curses.h> 48 #include <err.h> 49 #include <errno.h> 50 #include <fcntl.h> 51 #include <netdb.h> 52 #include <signal.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <limits.h> 58 #include <stdarg.h> 59 60 #include "systat.h" 61 #include "engine.h" 62 #include "cache.h" 63 64 extern const char *tcpstates[]; 65 66 #define MIN_NUM_STATES 1024 67 #define NUM_STATE_INC 1024 68 69 #define DEFAULT_CACHE_SIZE 10000 70 71 /* XXX must also check type before use */ 72 #define PT_ADDR(x) (&(x)->addr.v.a.addr) 73 74 /* XXX must also check type before use */ 75 #define PT_MASK(x) (&(x)->addr.v.a.mask) 76 77 #define PT_NOROUTE(x) ((x)->addr.type == PF_ADDR_NOROUTE) 78 79 /* view management */ 80 int select_states(void); 81 int read_states(void); 82 void sort_states(void); 83 void print_states(void); 84 85 int select_rules(void); 86 int read_rules(void); 87 void print_rules(void); 88 89 int select_queues(void); 90 int read_queues(void); 91 void print_queues(void); 92 93 void update_cache(void); 94 95 /* qsort callbacks */ 96 int sort_size_callback(const void *s1, const void *s2); 97 int sort_exp_callback(const void *s1, const void *s2); 98 int sort_pkt_callback(const void *s1, const void *s2); 99 int sort_age_callback(const void *s1, const void *s2); 100 int sort_sa_callback(const void *s1, const void *s2); 101 int sort_sp_callback(const void *s1, const void *s2); 102 int sort_da_callback(const void *s1, const void *s2); 103 int sort_dp_callback(const void *s1, const void *s2); 104 int sort_rate_callback(const void *s1, const void *s2); 105 int sort_peak_callback(const void *s1, const void *s2); 106 int pf_dev = -1; 107 108 struct sc_ent **state_cache = NULL; 109 struct pfsync_state *state_buf = NULL; 110 int state_buf_len = 0; 111 u_int32_t *state_ord = NULL; 112 u_int32_t num_states = 0; 113 u_int32_t num_states_all = 0; 114 u_int32_t num_rules = 0; 115 u_int32_t num_queues = 0; 116 int cachestates = 0; 117 118 char *filter_string = NULL; 119 120 #define MIN_LABEL_SIZE 5 121 #define ANCHOR_FLD_SIZE 12 122 123 /* Define fields */ 124 field_def fields[] = { 125 {"SRC", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 126 {"DEST", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 127 {"GW", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 128 {"STATE", 5, 23, 18, FLD_ALIGN_COLUMN, -1, 0, 0, 0}, 129 {"AGE", 5, 9, 4, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 130 {"EXP", 5, 9, 4, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 131 {"PR ", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 132 {"DIR", 1, 3, 2, FLD_ALIGN_CENTER, -1, 0, 0, 0}, 133 {"PKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 134 {"BYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 135 {"RULE", 2, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 136 {"LABEL", MIN_LABEL_SIZE, MIN_LABEL_SIZE, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 137 {"STATES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 138 {"EVAL", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 139 {"ACTION", 1, 8, 4, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 140 {"LOG", 1, 3, 2, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 141 {"QUICK", 1, 1, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 142 {"KS", 1, 1, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 143 {"IF", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 144 {"INFO", 40, 80, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 145 {"MAX", 3, 5, 2, FLD_ALIGN_RIGHT, -1, 0, 0}, 146 {"RATE", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 147 {"AVG", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 148 {"PEAK", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 149 {"ANCHOR", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0}, 150 {"QUEUE", 15, 30, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 151 {"BW", 4, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 152 {"SCH", 3, 4, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 153 {"PRIO", 1, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 154 {"DROP_P", 6, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 155 {"DROP_B", 6, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 156 {"QLEN", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 157 {"BORROW", 4, 6, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 158 {"SUSPENDS", 4, 6, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 159 {"P/S", 3, 7, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 160 {"B/S", 4, 7, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0} 161 }; 162 163 164 /* for states */ 165 #define FLD_SRC FIELD_ADDR(fields,0) 166 #define FLD_DEST FIELD_ADDR(fields,1) 167 #define FLD_GW FIELD_ADDR(fields,2) 168 #define FLD_STATE FIELD_ADDR(fields,3) 169 #define FLD_AGE FIELD_ADDR(fields,4) 170 #define FLD_EXP FIELD_ADDR(fields,5) 171 /* common */ 172 #define FLD_PROTO FIELD_ADDR(fields,6) 173 #define FLD_DIR FIELD_ADDR(fields,7) 174 #define FLD_PKTS FIELD_ADDR(fields,8) 175 #define FLD_BYTES FIELD_ADDR(fields,9) 176 #define FLD_RULE FIELD_ADDR(fields,10) 177 /* for rules */ 178 #define FLD_LABEL FIELD_ADDR(fields,11) 179 #define FLD_STATS FIELD_ADDR(fields,12) 180 #define FLD_EVAL FIELD_ADDR(fields,13) 181 #define FLD_ACTION FIELD_ADDR(fields,14) 182 #define FLD_LOG FIELD_ADDR(fields,15) 183 #define FLD_QUICK FIELD_ADDR(fields,16) 184 #define FLD_KST FIELD_ADDR(fields,17) 185 #define FLD_IF FIELD_ADDR(fields,18) 186 #define FLD_RINFO FIELD_ADDR(fields,19) 187 #define FLD_STMAX FIELD_ADDR(fields,20) 188 /* other */ 189 #define FLD_SI FIELD_ADDR(fields,21) /* instantaneous speed */ 190 #define FLD_SA FIELD_ADDR(fields,22) /* average speed */ 191 #define FLD_SP FIELD_ADDR(fields,23) /* peak speed */ 192 #define FLD_ANCHOR FIELD_ADDR(fields,24) 193 /* for queues */ 194 #define FLD_QUEUE FIELD_ADDR(fields,25) 195 #define FLD_BANDW FIELD_ADDR(fields,26) 196 #define FLD_SCHED FIELD_ADDR(fields,27) 197 #define FLD_PRIO FIELD_ADDR(fields,28) 198 #define FLD_DROPP FIELD_ADDR(fields,29) 199 #define FLD_DROPB FIELD_ADDR(fields,30) 200 #define FLD_QLEN FIELD_ADDR(fields,31) 201 #define FLD_BORR FIELD_ADDR(fields,32) 202 #define FLD_SUSP FIELD_ADDR(fields,33) 203 #define FLD_PKTSPS FIELD_ADDR(fields,34) 204 #define FLD_BYTESPS FIELD_ADDR(fields,35) 205 206 /* Define views */ 207 field_def *view0[] = { 208 FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_STATE, 209 FLD_AGE, FLD_EXP, FLD_PKTS, FLD_BYTES, NULL 210 }; 211 212 field_def *view1[] = { 213 FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_GW, FLD_STATE, FLD_AGE, 214 FLD_EXP, FLD_PKTS, FLD_BYTES, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, NULL 215 }; 216 217 field_def *view2[] = { 218 FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_STATE, FLD_AGE, FLD_EXP, 219 FLD_PKTS, FLD_BYTES, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL 220 }; 221 222 field_def *view3[] = { 223 FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_AGE, FLD_EXP, FLD_PKTS, 224 FLD_BYTES, FLD_STATE, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL 225 }; 226 227 field_def *view4[] = { 228 FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_PKTS, FLD_BYTES, FLD_STATE, 229 FLD_AGE, FLD_EXP, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL 230 }; 231 232 field_def *view5[] = { 233 FLD_RULE, FLD_ANCHOR, FLD_ACTION, FLD_DIR, FLD_LOG, FLD_QUICK, FLD_IF, 234 FLD_PROTO, FLD_KST, FLD_PKTS, FLD_BYTES, FLD_STATS, FLD_STMAX, 235 FLD_RINFO, NULL 236 }; 237 238 field_def *view6[] = { 239 FLD_RULE, FLD_LABEL, FLD_PKTS, FLD_BYTES, FLD_STATS, FLD_STMAX, 240 FLD_ACTION, FLD_DIR, FLD_LOG, FLD_QUICK, FLD_IF, FLD_PROTO, 241 FLD_ANCHOR, FLD_KST, NULL 242 }; 243 244 field_def *view7[] = { 245 FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_SI, FLD_SP, FLD_SA, 246 FLD_BYTES, FLD_STATE, FLD_PKTS, FLD_AGE, FLD_EXP, FLD_RULE, FLD_GW, NULL 247 }; 248 249 field_def *view8[] = { 250 FLD_QUEUE, FLD_BANDW, FLD_SCHED, FLD_PRIO, FLD_PKTS, FLD_BYTES, 251 FLD_DROPP, FLD_DROPB, FLD_QLEN, FLD_BORR, FLD_SUSP, FLD_PKTSPS, 252 FLD_BYTESPS, NULL 253 }; 254 255 /* Define orderings */ 256 order_type order_list[] = { 257 {"none", "none", 'N', NULL}, 258 {"bytes", "bytes", 'B', sort_size_callback}, 259 {"expiry", "exp", 'E', sort_exp_callback}, 260 {"packets", "pkt", 'P', sort_pkt_callback}, 261 {"age", "age", 'A', sort_age_callback}, 262 {"source addr", "src", 'F', sort_sa_callback}, 263 {"dest. addr", "dest", 'T', sort_da_callback}, 264 {"source port", "sport", 'S', sort_sp_callback}, 265 {"dest. port", "dport", 'D', sort_dp_callback}, 266 {"rate", "rate", 'R', sort_rate_callback}, 267 {"peak", "peak", 'K', sort_peak_callback}, 268 {NULL, NULL, 0, NULL} 269 }; 270 271 /* Define view managers */ 272 struct view_manager state_mgr = { 273 "States", select_states, read_states, sort_states, print_header, 274 print_states, keyboard_callback, order_list, NULL 275 }; 276 277 struct view_manager rule_mgr = { 278 "Rules", select_rules, read_rules, NULL, print_header, 279 print_rules, keyboard_callback, NULL, NULL 280 }; 281 282 struct view_manager queue_mgr = { 283 "Queues", select_queues, read_queues, NULL, print_header, 284 print_queues, keyboard_callback, NULL, NULL 285 }; 286 287 field_view views[] = { 288 {view2, "states", '8', &state_mgr}, 289 {view5, "rules", '9', &rule_mgr}, 290 {view8, "queues", 'Q', &queue_mgr}, 291 {NULL, NULL, 0, NULL} 292 }; 293 294 /* queue structures from pfctl */ 295 296 struct queue_stats { 297 struct hfsc_class_stats data; 298 int valid; 299 struct timeval timestamp; 300 }; 301 302 struct pfctl_queue_node { 303 TAILQ_ENTRY(pfctl_queue_node) entries; 304 struct pf_queuespec qs; 305 struct queue_stats qstats; 306 struct queue_stats qstats_last; 307 int depth; 308 }; 309 TAILQ_HEAD(qnodes, pfctl_queue_node) qnodes = TAILQ_HEAD_INITIALIZER(qnodes); 310 311 /* ordering functions */ 312 313 int 314 sort_size_callback(const void *s1, const void *s2) 315 { 316 u_int64_t b1 = COUNTER(state_buf[* (u_int32_t *) s1].bytes[0]) + 317 COUNTER(state_buf[* (u_int32_t *) s1].bytes[1]); 318 u_int64_t b2 = COUNTER(state_buf[* (u_int32_t *) s2].bytes[0]) + 319 COUNTER(state_buf[* (u_int32_t *) s2].bytes[1]); 320 if (b2 > b1) 321 return sortdir; 322 if (b2 < b1) 323 return -sortdir; 324 return 0; 325 } 326 327 int 328 sort_pkt_callback(const void *s1, const void *s2) 329 { 330 u_int64_t p1 = COUNTER(state_buf[* (u_int32_t *) s1].packets[0]) + 331 COUNTER(state_buf[* (u_int32_t *) s1].packets[1]); 332 u_int64_t p2 = COUNTER(state_buf[* (u_int32_t *) s2].packets[0]) + 333 COUNTER(state_buf[* (u_int32_t *) s2].packets[1]); 334 if (p2 > p1) 335 return sortdir; 336 if (p2 < p1) 337 return -sortdir; 338 return 0; 339 } 340 341 int 342 sort_age_callback(const void *s1, const void *s2) 343 { 344 if (ntohl(state_buf[* (u_int32_t *) s2].creation) > 345 ntohl(state_buf[* (u_int32_t *) s1].creation)) 346 return sortdir; 347 if (ntohl(state_buf[* (u_int32_t *) s2].creation) < 348 ntohl(state_buf[* (u_int32_t *) s1].creation)) 349 return -sortdir; 350 return 0; 351 } 352 353 int 354 sort_exp_callback(const void *s1, const void *s2) 355 { 356 if (ntohl(state_buf[* (u_int32_t *) s2].expire) > 357 ntohl(state_buf[* (u_int32_t *) s1].expire)) 358 return sortdir; 359 if (ntohl(state_buf[* (u_int32_t *) s2].expire) < 360 ntohl(state_buf[* (u_int32_t *) s1].expire)) 361 return -sortdir; 362 return 0; 363 } 364 365 int 366 sort_rate_callback(const void *s1, const void *s2) 367 { 368 struct sc_ent *e1 = state_cache[* (u_int32_t *) s1]; 369 struct sc_ent *e2 = state_cache[* (u_int32_t *) s2]; 370 371 if (e1 == NULL) 372 return sortdir; 373 if (e2 == NULL) 374 return -sortdir; 375 376 if (e2->rate > e1 -> rate) 377 return sortdir; 378 if (e2->rate < e1 -> rate) 379 return -sortdir; 380 return 0; 381 } 382 383 int 384 sort_peak_callback(const void *s1, const void *s2) 385 { 386 struct sc_ent *e1 = state_cache[* (u_int32_t *) s1]; 387 struct sc_ent *e2 = state_cache[* (u_int32_t *) s2]; 388 389 if (e2 == NULL) 390 return -sortdir; 391 if (e1 == NULL || e2 == NULL) 392 return 0; 393 394 if (e2->peak > e1 -> peak) 395 return sortdir; 396 if (e2->peak < e1 -> peak) 397 return -sortdir; 398 return 0; 399 } 400 401 int 402 compare_addr(int af, const struct pf_addr *a, const struct pf_addr *b) 403 { 404 switch (af) { 405 case AF_INET: 406 if (ntohl(a->addr32[0]) > ntohl(b->addr32[0])) 407 return 1; 408 if (a->addr32[0] != b->addr32[0]) 409 return -1; 410 break; 411 case AF_INET6: 412 if (ntohl(a->addr32[0]) > ntohl(b->addr32[0])) 413 return 1; 414 if (a->addr32[0] != b->addr32[0]) 415 return -1; 416 if (ntohl(a->addr32[1]) > ntohl(b->addr32[1])) 417 return 1; 418 if (a->addr32[1] != b->addr32[1]) 419 return -1; 420 if (ntohl(a->addr32[2]) > ntohl(b->addr32[2])) 421 return 1; 422 if (a->addr32[2] != b->addr32[2]) 423 return -1; 424 if (ntohl(a->addr32[3]) > ntohl(b->addr32[3])) 425 return 1; 426 if (a->addr32[3] != b->addr32[3]) 427 return -1; 428 break; 429 } 430 431 return 0; 432 } 433 434 static __inline int 435 sort_addr_callback(const struct pfsync_state *s1, 436 const struct pfsync_state *s2, int dir) 437 { 438 const struct pf_addr *aa, *ab; 439 u_int16_t pa, pb; 440 int af, side, ret, ii, io; 441 442 side = s1->direction == PF_IN ? PF_SK_STACK : PF_SK_WIRE; 443 444 if (s1->key[side].af > s2->key[side].af) 445 return sortdir; 446 if (s1->key[side].af < s2->key[side].af) 447 return -sortdir; 448 449 ii = io = 0; 450 451 if (dir == PF_OUT) /* looking for source addr */ 452 io = 1; 453 else /* looking for dest addr */ 454 ii = 1; 455 456 if (s1->key[PF_SK_STACK].af != s1->key[PF_SK_WIRE].af) { 457 dir = PF_OUT; 458 side = PF_SK_STACK; 459 } else { 460 dir = s1->direction; 461 side = PF_SK_WIRE; 462 } 463 464 if (dir == PF_IN) { 465 aa = &s1->key[PF_SK_STACK].addr[ii]; 466 pa = s1->key[PF_SK_STACK].port[ii]; 467 af = s1->key[PF_SK_STACK].af; 468 } else { 469 aa = &s1->key[side].addr[io]; 470 pa = s1->key[side].port[io]; 471 af = s1->key[side].af; 472 } 473 474 if (s2->key[PF_SK_STACK].af != s2->key[PF_SK_WIRE].af) { 475 dir = PF_OUT; 476 side = PF_SK_STACK; 477 } else { 478 dir = s2->direction; 479 side = PF_SK_WIRE; 480 } 481 482 if (dir == PF_IN) { 483 ab = &s2->key[PF_SK_STACK].addr[ii]; 484 pb = s2->key[PF_SK_STACK].port[ii]; 485 af = s1->key[PF_SK_STACK].af; 486 } else { 487 ab = &s2->key[side].addr[io]; 488 pb = s2->key[side].port[io]; 489 af = s1->key[side].af; 490 } 491 492 ret = compare_addr(af, aa, ab); 493 if (ret) 494 return ret * sortdir; 495 496 if (ntohs(pa) > ntohs(pb)) 497 return sortdir; 498 return -sortdir; 499 } 500 501 static __inline int 502 sort_port_callback(const struct pfsync_state *s1, 503 const struct pfsync_state *s2, int dir) 504 { 505 const struct pf_addr *aa, *ab; 506 u_int16_t pa, pb; 507 int af, side, ret, ii, io; 508 509 side = s1->direction == PF_IN ? PF_SK_STACK : PF_SK_WIRE; 510 511 if (s1->key[side].af > s2->key[side].af) 512 return sortdir; 513 if (s1->key[side].af < s2->key[side].af) 514 return -sortdir; 515 516 ii = io = 0; 517 518 if (dir == PF_OUT) /* looking for source addr */ 519 io = 1; 520 else /* looking for dest addr */ 521 ii = 1; 522 523 if (s1->key[PF_SK_STACK].af != s1->key[PF_SK_WIRE].af) { 524 dir = PF_OUT; 525 side = PF_SK_STACK; 526 } else { 527 dir = s1->direction; 528 side = PF_SK_WIRE; 529 } 530 531 if (dir == PF_IN) { 532 aa = &s1->key[PF_SK_STACK].addr[ii]; 533 pa = s1->key[PF_SK_STACK].port[ii]; 534 af = s1->key[PF_SK_STACK].af; 535 } else { 536 aa = &s1->key[side].addr[io]; 537 pa = s1->key[side].port[io]; 538 af = s1->key[side].af; 539 } 540 541 if (s2->key[PF_SK_STACK].af != s2->key[PF_SK_WIRE].af) { 542 dir = PF_OUT; 543 side = PF_SK_STACK; 544 } else { 545 dir = s2->direction; 546 side = PF_SK_WIRE; 547 } 548 549 if (dir == PF_IN) { 550 ab = &s2->key[PF_SK_STACK].addr[ii]; 551 pb = s2->key[PF_SK_STACK].port[ii]; 552 af = s1->key[PF_SK_STACK].af; 553 } else { 554 ab = &s2->key[side].addr[io]; 555 pb = s2->key[side].port[io]; 556 af = s1->key[side].af; 557 } 558 559 560 if (ntohs(pa) > ntohs(pb)) 561 return sortdir; 562 if (ntohs(pa) < ntohs(pb)) 563 return - sortdir; 564 565 ret = compare_addr(af, aa, ab); 566 if (ret) 567 return ret * sortdir; 568 return -sortdir; 569 } 570 571 int 572 sort_sa_callback(const void *p1, const void *p2) 573 { 574 struct pfsync_state *s1 = state_buf + (* (u_int32_t *) p1); 575 struct pfsync_state *s2 = state_buf + (* (u_int32_t *) p2); 576 return sort_addr_callback(s1, s2, PF_OUT); 577 } 578 579 int 580 sort_da_callback(const void *p1, const void *p2) 581 { 582 struct pfsync_state *s1 = state_buf + (* (u_int32_t *) p1); 583 struct pfsync_state *s2 = state_buf + (* (u_int32_t *) p2); 584 return sort_addr_callback(s1, s2, PF_IN); 585 } 586 587 int 588 sort_sp_callback(const void *p1, const void *p2) 589 { 590 struct pfsync_state *s1 = state_buf + (* (u_int32_t *) p1); 591 struct pfsync_state *s2 = state_buf + (* (u_int32_t *) p2); 592 return sort_port_callback(s1, s2, PF_OUT); 593 } 594 595 int 596 sort_dp_callback(const void *p1, const void *p2) 597 { 598 struct pfsync_state *s1 = state_buf + (* (u_int32_t *) p1); 599 struct pfsync_state *s2 = state_buf + (* (u_int32_t *) p2); 600 return sort_port_callback(s1, s2, PF_IN); 601 } 602 603 void 604 sort_states(void) 605 { 606 order_type *ordering; 607 608 if (curr_mgr == NULL) 609 return; 610 611 ordering = curr_mgr->order_curr; 612 613 if (ordering == NULL) 614 return; 615 if (ordering->func == NULL) 616 return; 617 if (state_buf == NULL) 618 return; 619 if (num_states <= 0) 620 return; 621 622 mergesort(state_ord, num_states, sizeof(u_int32_t), ordering->func); 623 } 624 625 /* state management functions */ 626 627 void 628 alloc_buf(int ns) 629 { 630 int len; 631 632 if (ns < MIN_NUM_STATES) 633 ns = MIN_NUM_STATES; 634 635 len = ns; 636 637 if (len >= state_buf_len) { 638 len += NUM_STATE_INC; 639 state_buf = reallocarray(state_buf, len, 640 sizeof(struct pfsync_state)); 641 state_ord = reallocarray(state_ord, len, sizeof(u_int32_t)); 642 state_cache = reallocarray(state_cache, len, 643 sizeof(struct sc_ent *)); 644 if (state_buf == NULL || state_ord == NULL || 645 state_cache == NULL) 646 err(1, "realloc"); 647 state_buf_len = len; 648 } 649 } 650 651 int 652 select_states(void) 653 { 654 num_disp = num_states; 655 return (0); 656 } 657 658 int 659 read_states(void) 660 { 661 struct pfioc_states ps; 662 int n; 663 664 if (pf_dev == -1) 665 return -1; 666 667 for (;;) { 668 int sbytes = state_buf_len * sizeof(struct pfsync_state); 669 670 ps.ps_len = sbytes; 671 ps.ps_buf = (char *) state_buf; 672 673 if (ioctl(pf_dev, DIOCGETSTATES, &ps) < 0) { 674 error("DIOCGETSTATES"); 675 } 676 num_states_all = ps.ps_len / sizeof(struct pfsync_state); 677 678 if (ps.ps_len < sbytes) 679 break; 680 681 alloc_buf(num_states_all); 682 } 683 684 num_states = num_states_all; 685 for (n = 0; n<num_states_all; n++) 686 state_ord[n] = n; 687 688 if (cachestates) { 689 for (n = 0; n < num_states; n++) 690 state_cache[n] = cache_state(state_buf + n); 691 cache_endupdate(); 692 } 693 694 num_disp = num_states; 695 return 0; 696 } 697 698 int 699 unmask(struct pf_addr * m, u_int8_t af) 700 { 701 int i = 31, j = 0, b = 0, msize; 702 u_int32_t tmp; 703 704 if (af == AF_INET) 705 msize = 1; 706 else 707 msize = 4; 708 while (j < msize && m->addr32[j] == 0xffffffff) { 709 b += 32; 710 j++; 711 } 712 if (j < msize) { 713 tmp = ntohl(m->addr32[j]); 714 for (i = 31; tmp & (1 << i); --i) 715 b++; 716 } 717 return (b); 718 } 719 720 /* display functions */ 721 722 void 723 tb_print_addr(struct pf_addr * addr, struct pf_addr * mask, int af) 724 { 725 switch (af) { 726 case AF_INET: { 727 tbprintf("%s", inetname(addr->v4)); 728 break; 729 } 730 case AF_INET6: { 731 tbprintf("%s", inet6name(&addr->v6)); 732 break; 733 } 734 } 735 736 if (mask != NULL) { 737 if (!PF_AZERO(mask, af)) 738 tbprintf("/%u", unmask(mask, af)); 739 } 740 } 741 742 void 743 print_fld_host2(field_def *fld, struct pfsync_state_key *ks, 744 struct pfsync_state_key *kn, int idx) 745 { 746 struct pf_addr *as = &ks->addr[idx]; 747 struct pf_addr *an = &kn->addr[idx]; 748 749 u_int16_t ps = ntohs(ks->port[idx]); 750 u_int16_t pn = ntohs(kn->port[idx]); 751 752 int asf = ks->af; 753 int anf = kn->af; 754 755 if (fld == NULL) 756 return; 757 758 if (fld->width < 3) { 759 print_fld_str(fld, "*"); 760 return; 761 } 762 763 tb_start(); 764 tb_print_addr(as, NULL, asf); 765 766 if (asf == AF_INET) 767 tbprintf(":%u", ps); 768 else 769 tbprintf("[%u]", ps); 770 771 print_fld_tb(fld); 772 773 if (asf != anf || PF_ANEQ(as, an, asf) || ps != pn) { 774 tb_start(); 775 tb_print_addr(an, NULL, anf); 776 777 if (anf == AF_INET) 778 tbprintf(":%u", pn); 779 else 780 tbprintf("[%u]", pn); 781 print_fld_tb(FLD_GW); 782 } 783 784 } 785 786 void 787 print_fld_state(field_def *fld, unsigned int proto, 788 unsigned int s1, unsigned int s2) 789 { 790 int len; 791 792 if (fld == NULL) 793 return; 794 795 len = fld->width; 796 if (len < 1) 797 return; 798 799 tb_start(); 800 801 if (proto == IPPROTO_TCP) { 802 if (s1 <= TCPS_TIME_WAIT && s2 <= TCPS_TIME_WAIT) 803 tbprintf("%s:%s", tcpstates[s1], tcpstates[s2]); 804 #ifdef PF_TCPS_PROXY_SRC 805 else if (s1 == PF_TCPS_PROXY_SRC || 806 s2 == PF_TCPS_PROXY_SRC) 807 tbprintf("PROXY:SRC\n"); 808 else if (s1 == PF_TCPS_PROXY_DST || 809 s2 == PF_TCPS_PROXY_DST) 810 tbprintf("PROXY:DST\n"); 811 #endif 812 else 813 tbprintf("<BAD STATE LEVELS>"); 814 } else if (proto == IPPROTO_UDP && s1 < PFUDPS_NSTATES && 815 s2 < PFUDPS_NSTATES) { 816 const char *states[] = PFUDPS_NAMES; 817 tbprintf("%s:%s", states[s1], states[s2]); 818 } else if (proto != IPPROTO_ICMP && s1 < PFOTHERS_NSTATES && 819 s2 < PFOTHERS_NSTATES) { 820 /* XXX ICMP doesn't really have state levels */ 821 const char *states[] = PFOTHERS_NAMES; 822 tbprintf("%s:%s", states[s1], states[s2]); 823 } else { 824 tbprintf("%u:%u", s1, s2); 825 } 826 827 if (strlen(tmp_buf) > len) { 828 tb_start(); 829 tbprintf("%u:%u", s1, s2); 830 } 831 832 print_fld_tb(fld); 833 } 834 835 int 836 print_state(struct pfsync_state * s, struct sc_ent * ent) 837 { 838 struct pfsync_state_peer *src, *dst; 839 struct protoent *p; 840 u_int64_t sz; 841 int afto, dir; 842 843 afto = s->key[PF_SK_STACK].af == s->key[PF_SK_WIRE].af ? 0 : 1; 844 dir = afto ? PF_OUT : s->direction; 845 846 if (dir == PF_OUT) { 847 src = &s->src; 848 dst = &s->dst; 849 } else { 850 src = &s->dst; 851 dst = &s->src; 852 } 853 854 p = getprotobynumber(s->proto); 855 856 if (p != NULL) 857 print_fld_str(FLD_PROTO, p->p_name); 858 else 859 print_fld_uint(FLD_PROTO, s->proto); 860 861 if (dir == PF_OUT) { 862 print_fld_host2(FLD_SRC, 863 &s->key[afto ? PF_SK_STACK : PF_SK_WIRE], 864 &s->key[PF_SK_STACK], 1); 865 print_fld_host2(FLD_DEST, 866 &s->key[afto ? PF_SK_STACK : PF_SK_WIRE], 867 &s->key[afto ? PF_SK_WIRE : PF_SK_STACK], 0); 868 } else { 869 print_fld_host2(FLD_SRC, &s->key[PF_SK_STACK], 870 &s->key[PF_SK_WIRE], 0); 871 print_fld_host2(FLD_DEST, &s->key[PF_SK_STACK], 872 &s->key[PF_SK_WIRE], 1); 873 } 874 875 if (dir == PF_OUT) 876 print_fld_str(FLD_DIR, "Out"); 877 else 878 print_fld_str(FLD_DIR, "In"); 879 880 print_fld_state(FLD_STATE, s->proto, src->state, dst->state); 881 print_fld_age(FLD_AGE, ntohl(s->creation)); 882 print_fld_age(FLD_EXP, ntohl(s->expire)); 883 884 sz = COUNTER(s->bytes[0]) + COUNTER(s->bytes[1]); 885 886 print_fld_size(FLD_PKTS, COUNTER(s->packets[0]) + 887 COUNTER(s->packets[1])); 888 print_fld_size(FLD_BYTES, sz); 889 print_fld_rate(FLD_SA, (s->creation) ? 890 ((double)sz/(double)ntohl(s->creation)) : -1); 891 892 print_fld_uint(FLD_RULE, ntohl(s->rule)); 893 if (cachestates && ent != NULL) { 894 print_fld_rate(FLD_SI, ent->rate); 895 print_fld_rate(FLD_SP, ent->peak); 896 } 897 898 end_line(); 899 return 1; 900 } 901 902 void 903 print_states(void) 904 { 905 int n, count = 0; 906 907 for (n = dispstart; n < num_disp; n++) { 908 count += print_state(state_buf + state_ord[n], 909 state_cache[state_ord[n]]); 910 if (maxprint > 0 && count >= maxprint) 911 break; 912 } 913 } 914 915 /* rule display */ 916 917 struct pf_rule *rules = NULL; 918 u_int32_t alloc_rules = 0; 919 920 int 921 select_rules(void) 922 { 923 num_disp = num_rules; 924 return (0); 925 } 926 927 928 void 929 add_rule_alloc(u_int32_t nr) 930 { 931 if (nr == 0) 932 return; 933 934 num_rules += nr; 935 936 if (rules == NULL) { 937 rules = reallocarray(NULL, num_rules, sizeof(struct pf_rule)); 938 if (rules == NULL) 939 err(1, "malloc"); 940 alloc_rules = num_rules; 941 } else if (num_rules > alloc_rules) { 942 rules = reallocarray(rules, num_rules, sizeof(struct pf_rule)); 943 if (rules == NULL) 944 err(1, "realloc"); 945 alloc_rules = num_rules; 946 } 947 } 948 949 int label_length; 950 951 int 952 read_anchor_rules(char *anchor) 953 { 954 struct pfioc_rule pr; 955 u_int32_t nr, num, off; 956 int len; 957 958 if (pf_dev < 0) 959 return (-1); 960 961 memset(&pr, 0, sizeof(pr)); 962 strlcpy(pr.anchor, anchor, sizeof(pr.anchor)); 963 964 if (ioctl(pf_dev, DIOCGETRULES, &pr)) { 965 error("anchor %s: %s", anchor, strerror(errno)); 966 return (-1); 967 } 968 969 off = num_rules; 970 num = pr.nr; 971 add_rule_alloc(num); 972 973 for (nr = 0; nr < num; ++nr) { 974 pr.nr = nr; 975 if (ioctl(pf_dev, DIOCGETRULE, &pr)) { 976 error("DIOCGETRULE: %s", strerror(errno)); 977 return (-1); 978 } 979 /* XXX overload pr.anchor, to store a pointer to 980 * anchor name */ 981 pr.rule.anchor = (struct pf_anchor *) anchor; 982 len = strlen(pr.rule.label); 983 if (len > label_length) 984 label_length = len; 985 rules[off + nr] = pr.rule; 986 } 987 988 return (num); 989 } 990 991 struct anchor_name { 992 char name[PATH_MAX]; 993 struct anchor_name *next; 994 u_int32_t ref; 995 }; 996 997 struct anchor_name *anchor_root = NULL; 998 struct anchor_name *anchor_end = NULL; 999 struct anchor_name *anchor_free = NULL; 1000 1001 struct anchor_name* 1002 alloc_anchor_name(const char *path) 1003 { 1004 struct anchor_name *a; 1005 1006 a = anchor_free; 1007 if (a == NULL) { 1008 a = malloc(sizeof(struct anchor_name)); 1009 if (a == NULL) 1010 return (NULL); 1011 } else 1012 anchor_free = a->next; 1013 1014 if (anchor_root == NULL) 1015 anchor_end = a; 1016 1017 a->next = anchor_root; 1018 anchor_root = a; 1019 1020 a->ref = 0; 1021 strlcpy(a->name, path, sizeof(a->name)); 1022 return (a); 1023 } 1024 1025 void 1026 reset_anchor_names(void) 1027 { 1028 if (anchor_end == NULL) 1029 return; 1030 1031 anchor_end->next = anchor_free; 1032 anchor_free = anchor_root; 1033 anchor_root = anchor_end = NULL; 1034 } 1035 1036 struct pfioc_ruleset ruleset; 1037 char *rs_end = NULL; 1038 1039 int 1040 read_rulesets(const char *path) 1041 { 1042 char *pre; 1043 struct anchor_name *a; 1044 u_int32_t nr, ns; 1045 int len; 1046 1047 if (path == NULL) 1048 ruleset.path[0] = '\0'; 1049 else if (strlcpy(ruleset.path, path, sizeof(ruleset.path)) >= 1050 sizeof(ruleset.path)) 1051 return (-1); 1052 1053 /* a persistent storage for anchor names */ 1054 a = alloc_anchor_name(ruleset.path); 1055 if (a == NULL) 1056 return (-1); 1057 1058 len = read_anchor_rules(a->name); 1059 if (len < 0) 1060 return (-1); 1061 1062 a->ref += len; 1063 1064 if (ioctl(pf_dev, DIOCGETRULESETS, &ruleset)) { 1065 error("DIOCGETRULESETS: %s", strerror(errno)); 1066 return (-1); 1067 } 1068 1069 ns = ruleset.nr; 1070 1071 if (rs_end == NULL) 1072 rs_end = ruleset.path + sizeof(ruleset.path); 1073 1074 /* 'pre' tracks the previous level on the anchor */ 1075 pre = strchr(ruleset.path, 0); 1076 len = rs_end - pre; 1077 if (len < 1) 1078 return (-1); 1079 --len; 1080 1081 for (nr = 0; nr < ns; ++nr) { 1082 ruleset.nr = nr; 1083 if (ioctl(pf_dev, DIOCGETRULESET, &ruleset)) { 1084 error("DIOCGETRULESET: %s", strerror(errno)); 1085 return (-1); 1086 } 1087 *pre = '/'; 1088 if (strlcpy(pre + 1, ruleset.name, len) < len) 1089 read_rulesets(ruleset.path); 1090 *pre = '\0'; 1091 } 1092 1093 return (0); 1094 } 1095 1096 void 1097 compute_anchor_field(void) 1098 { 1099 struct anchor_name *a; 1100 int sum, cnt, mx, nx; 1101 sum = cnt = mx = 0; 1102 1103 for (a = anchor_root; a != NULL; a = a->next, cnt++) { 1104 int len; 1105 if (a->ref == 0) 1106 continue; 1107 len = strlen(a->name); 1108 sum += len; 1109 if (len > mx) 1110 mx = len; 1111 } 1112 1113 nx = sum/cnt; 1114 if (nx < ANCHOR_FLD_SIZE) 1115 nx = (mx < ANCHOR_FLD_SIZE) ? mx : ANCHOR_FLD_SIZE; 1116 1117 if (FLD_ANCHOR->max_width != mx || 1118 FLD_ANCHOR->norm_width != nx) { 1119 FLD_ANCHOR->max_width = mx; 1120 FLD_ANCHOR->norm_width = nx; 1121 field_setup(); 1122 need_update = 1; 1123 } 1124 } 1125 1126 int 1127 read_rules(void) 1128 { 1129 int ret, nw, mw; 1130 num_rules = 0; 1131 1132 if (pf_dev == -1) 1133 return (-1); 1134 1135 label_length = MIN_LABEL_SIZE; 1136 1137 reset_anchor_names(); 1138 ret = read_rulesets(NULL); 1139 compute_anchor_field(); 1140 1141 nw = mw = label_length; 1142 if (nw > 16) 1143 nw = 16; 1144 1145 if (FLD_LABEL->norm_width != nw || 1146 FLD_LABEL->max_width != mw) { 1147 FLD_LABEL->norm_width = nw; 1148 FLD_LABEL->max_width = mw; 1149 field_setup(); 1150 need_update = 1; 1151 } 1152 1153 num_disp = num_rules; 1154 return (ret); 1155 } 1156 1157 void 1158 tb_print_addrw(struct pf_addr_wrap *addr, struct pf_addr *mask, u_int8_t af) 1159 { 1160 switch (addr->type) { 1161 case PF_ADDR_ADDRMASK: 1162 tb_print_addr(&addr->v.a.addr, mask, af); 1163 break; 1164 case PF_ADDR_NOROUTE: 1165 tbprintf("noroute"); 1166 break; 1167 case PF_ADDR_DYNIFTL: 1168 tbprintf("(%s)", addr->v.ifname); 1169 break; 1170 case PF_ADDR_TABLE: 1171 tbprintf("<%s>", addr->v.tblname); 1172 break; 1173 default: 1174 tbprintf("UNKNOWN"); 1175 break; 1176 } 1177 } 1178 1179 void 1180 tb_print_op(u_int8_t op, const char *a1, const char *a2) 1181 { 1182 if (op == PF_OP_IRG) 1183 tbprintf("%s >< %s ", a1, a2); 1184 else if (op == PF_OP_XRG) 1185 tbprintf("%s <> %s ", a1, a2); 1186 else if (op == PF_OP_RRG) 1187 tbprintf("%s:%s ", a1, a2); 1188 else if (op == PF_OP_EQ) 1189 tbprintf("= %s ", a1); 1190 else if (op == PF_OP_NE) 1191 tbprintf("!= %s ", a1); 1192 else if (op == PF_OP_LT) 1193 tbprintf("< %s ", a1); 1194 else if (op == PF_OP_LE) 1195 tbprintf("<= %s ", a1); 1196 else if (op == PF_OP_GT) 1197 tbprintf("> %s ", a1); 1198 else if (op == PF_OP_GE) 1199 tbprintf(">= %s ", a1); 1200 } 1201 1202 void 1203 tb_print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto) 1204 { 1205 char a1[6], a2[6]; 1206 struct servent *s = getservbyport(p1, proto); 1207 1208 p1 = ntohs(p1); 1209 p2 = ntohs(p2); 1210 snprintf(a1, sizeof(a1), "%u", p1); 1211 snprintf(a2, sizeof(a2), "%u", p2); 1212 tbprintf("port "); 1213 if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) 1214 tb_print_op(op, s->s_name, a2); 1215 else 1216 tb_print_op(op, a1, a2); 1217 } 1218 1219 void 1220 tb_print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst, 1221 u_int8_t af, u_int8_t proto) 1222 { 1223 if ( 1224 PF_AZERO(PT_ADDR(src), AF_INET6) && 1225 PF_AZERO(PT_ADDR(dst), AF_INET6) && 1226 ! PT_NOROUTE(src) && ! PT_NOROUTE(dst) && 1227 PF_AZERO(PT_MASK(src), AF_INET6) && 1228 PF_AZERO(PT_MASK(dst), AF_INET6) && 1229 !src->port_op && !dst->port_op) 1230 tbprintf("all "); 1231 else { 1232 tbprintf("from "); 1233 if (PT_NOROUTE(src)) 1234 tbprintf("no-route "); 1235 else if (PF_AZERO(PT_ADDR(src), AF_INET6) && 1236 PF_AZERO(PT_MASK(src), AF_INET6)) 1237 tbprintf("any "); 1238 else { 1239 if (src->neg) 1240 tbprintf("! "); 1241 tb_print_addrw(&src->addr, PT_MASK(src), af); 1242 tbprintf(" "); 1243 } 1244 if (src->port_op) 1245 tb_print_port(src->port_op, src->port[0], 1246 src->port[1], 1247 proto == IPPROTO_TCP ? "tcp" : "udp"); 1248 1249 tbprintf("to "); 1250 if (PT_NOROUTE(dst)) 1251 tbprintf("no-route "); 1252 else if (PF_AZERO(PT_ADDR(dst), AF_INET6) && 1253 PF_AZERO(PT_MASK(dst), AF_INET6)) 1254 tbprintf("any "); 1255 else { 1256 if (dst->neg) 1257 tbprintf("! "); 1258 tb_print_addrw(&dst->addr, PT_MASK(dst), af); 1259 tbprintf(" "); 1260 } 1261 if (dst->port_op) 1262 tb_print_port(dst->port_op, dst->port[0], 1263 dst->port[1], 1264 proto == IPPROTO_TCP ? "tcp" : "udp"); 1265 } 1266 } 1267 1268 void 1269 tb_print_ugid(u_int8_t op, unsigned u1, unsigned u2, 1270 const char *t, unsigned umax) 1271 { 1272 char a1[11], a2[11]; 1273 1274 snprintf(a1, sizeof(a1), "%u", u1); 1275 snprintf(a2, sizeof(a2), "%u", u2); 1276 1277 tbprintf("%s ", t); 1278 if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) 1279 tb_print_op(op, "unknown", a2); 1280 else 1281 tb_print_op(op, a1, a2); 1282 } 1283 1284 void 1285 tb_print_flags(u_int8_t f) 1286 { 1287 const char *tcpflags = "FSRPAUEW"; 1288 int i; 1289 1290 for (i = 0; tcpflags[i]; ++i) 1291 if (f & (1 << i)) 1292 tbprintf("%c", tcpflags[i]); 1293 } 1294 1295 void 1296 print_rule(struct pf_rule *pr) 1297 { 1298 static const char *actiontypes[] = { "Pass", "Block", "Scrub", 1299 "no Scrub", "Nat", "no Nat", "Binat", "no Binat", "Rdr", 1300 "no Rdr", "SynProxy Block", "Defer", "Match" }; 1301 int numact = sizeof(actiontypes) / sizeof(char *); 1302 1303 static const char *routetypes[] = { "", "fastroute", "route-to", 1304 "dup-to", "reply-to" }; 1305 1306 int numroute = sizeof(routetypes) / sizeof(char *); 1307 1308 if (pr == NULL) return; 1309 1310 print_fld_str(FLD_LABEL, pr->label); 1311 print_fld_size(FLD_STATS, pr->states_tot); 1312 1313 print_fld_size(FLD_PKTS, pr->packets[0] + pr->packets[1]); 1314 print_fld_size(FLD_BYTES, pr->bytes[0] + pr->bytes[1]); 1315 1316 print_fld_uint(FLD_RULE, pr->nr); 1317 if (pr->direction == PF_OUT) 1318 print_fld_str(FLD_DIR, "Out"); 1319 else if (pr->direction == PF_IN) 1320 print_fld_str(FLD_DIR, "In"); 1321 else 1322 print_fld_str(FLD_DIR, "Any"); 1323 1324 if (pr->quick) 1325 print_fld_str(FLD_QUICK, "Quick"); 1326 1327 if (pr->keep_state == PF_STATE_NORMAL) 1328 print_fld_str(FLD_KST, "Keep"); 1329 else if (pr->keep_state == PF_STATE_MODULATE) 1330 print_fld_str(FLD_KST, "Mod"); 1331 else if (pr->keep_state == PF_STATE_SYNPROXY) 1332 print_fld_str(FLD_KST, "Syn"); 1333 if (pr->log == 1) 1334 print_fld_str(FLD_LOG, "Log"); 1335 else if (pr->log == 2) 1336 print_fld_str(FLD_LOG, "All"); 1337 1338 if (pr->action >= numact) 1339 print_fld_uint(FLD_ACTION, pr->action); 1340 else print_fld_str(FLD_ACTION, actiontypes[pr->action]); 1341 1342 if (pr->proto) { 1343 struct protoent *p = getprotobynumber(pr->proto); 1344 1345 if (p != NULL) 1346 print_fld_str(FLD_PROTO, p->p_name); 1347 else 1348 print_fld_uint(FLD_PROTO, pr->proto); 1349 } 1350 1351 if (pr->ifname[0]) { 1352 tb_start(); 1353 if (pr->ifnot) 1354 tbprintf("!"); 1355 tbprintf("%s", pr->ifname); 1356 print_fld_tb(FLD_IF); 1357 } 1358 if (pr->max_states) 1359 print_fld_uint(FLD_STMAX, pr->max_states); 1360 1361 /* print info field */ 1362 1363 tb_start(); 1364 1365 if (pr->action == PF_DROP) { 1366 if (pr->rule_flag & PFRULE_RETURNRST) 1367 tbprintf("return-rst "); 1368 #ifdef PFRULE_RETURN 1369 else if (pr->rule_flag & PFRULE_RETURN) 1370 tbprintf("return "); 1371 #endif 1372 #ifdef PFRULE_RETURNICMP 1373 else if (pr->rule_flag & PFRULE_RETURNICMP) 1374 tbprintf("return-icmp "); 1375 #endif 1376 else 1377 tbprintf("drop "); 1378 } 1379 1380 if (pr->rt > 0 && pr->rt < numroute) { 1381 tbprintf("%s ", routetypes[pr->rt]); 1382 } 1383 1384 if (pr->af) { 1385 if (pr->af == AF_INET) 1386 tbprintf("inet "); 1387 else 1388 tbprintf("inet6 "); 1389 } 1390 1391 tb_print_fromto(&pr->src, &pr->dst, pr->af, pr->proto); 1392 1393 if (pr->uid.op) 1394 tb_print_ugid(pr->uid.op, pr->uid.uid[0], pr->uid.uid[1], 1395 "user", UID_MAX); 1396 if (pr->gid.op) 1397 tb_print_ugid(pr->gid.op, pr->gid.gid[0], pr->gid.gid[1], 1398 "group", GID_MAX); 1399 1400 if (pr->action == PF_PASS && 1401 (pr->proto == 0 || pr->proto == IPPROTO_TCP) && 1402 (pr->flags != TH_SYN || pr->flagset != (TH_SYN | TH_ACK) )) { 1403 tbprintf("flags "); 1404 if (pr->flags || pr->flagset) { 1405 tb_print_flags(pr->flags); 1406 tbprintf("/"); 1407 tb_print_flags(pr->flagset); 1408 } else 1409 tbprintf("any "); 1410 } 1411 1412 tbprintf(" "); 1413 1414 if (pr->tos) 1415 tbprintf("tos 0x%2.2x ", pr->tos); 1416 #ifdef PFRULE_FRAGMENT 1417 if (pr->rule_flag & PFRULE_FRAGMENT) 1418 tbprintf("fragment "); 1419 #endif 1420 #ifdef PFRULE_NODF 1421 if (pr->rule_flag & PFRULE_NODF) 1422 tbprintf("no-df "); 1423 #endif 1424 #ifdef PFRULE_RANDOMID 1425 if (pr->rule_flag & PFRULE_RANDOMID) 1426 tbprintf("random-id "); 1427 #endif 1428 if (pr->min_ttl) 1429 tbprintf("min-ttl %d ", pr->min_ttl); 1430 if (pr->max_mss) 1431 tbprintf("max-mss %d ", pr->max_mss); 1432 if (pr->allow_opts) 1433 tbprintf("allow-opts "); 1434 1435 /* XXX more missing */ 1436 1437 if (pr->qname[0] && pr->pqname[0]) 1438 tbprintf("queue(%s, %s) ", pr->qname, pr->pqname); 1439 else if (pr->qname[0]) 1440 tbprintf("queue %s ", pr->qname); 1441 1442 if (pr->tagname[0]) 1443 tbprintf("tag %s ", pr->tagname); 1444 if (pr->match_tagname[0]) { 1445 if (pr->match_tag_not) 1446 tbprintf("! "); 1447 tbprintf("tagged %s ", pr->match_tagname); 1448 } 1449 1450 print_fld_tb(FLD_RINFO); 1451 1452 /* XXX anchor field overloaded with anchor name */ 1453 print_fld_str(FLD_ANCHOR, (char *)pr->anchor); 1454 tb_end(); 1455 1456 end_line(); 1457 } 1458 1459 void 1460 print_rules(void) 1461 { 1462 u_int32_t n, count = 0; 1463 1464 for (n = dispstart; n < num_rules; n++) { 1465 print_rule(rules + n); 1466 count ++; 1467 if (maxprint > 0 && count >= maxprint) 1468 break; 1469 } 1470 } 1471 1472 /* queue display */ 1473 struct pfctl_queue_node * 1474 pfctl_find_queue_node(const char *qname, const char *ifname) 1475 { 1476 struct pfctl_queue_node *node; 1477 1478 TAILQ_FOREACH(node, &qnodes, entries) 1479 if (!strcmp(node->qs.qname, qname) 1480 && !(strcmp(node->qs.ifname, ifname))) 1481 return (node); 1482 return (NULL); 1483 } 1484 1485 void 1486 pfctl_insert_queue_node(const struct pf_queuespec qs, 1487 const struct queue_stats qstats) 1488 { 1489 struct pfctl_queue_node *node, *parent; 1490 1491 node = calloc(1, sizeof(struct pfctl_queue_node)); 1492 if (node == NULL) 1493 err(1, "pfctl_insert_queue_node: calloc"); 1494 memcpy(&node->qs, &qs, sizeof(qs)); 1495 memcpy(&node->qstats, &qstats, sizeof(qstats)); 1496 1497 if (node->qs.parent[0]) { 1498 parent = pfctl_find_queue_node(node->qs.parent, 1499 node->qs.ifname); 1500 if (parent) 1501 node->depth = parent->depth + 1; 1502 } 1503 1504 TAILQ_INSERT_TAIL(&qnodes, node, entries); 1505 } 1506 1507 int 1508 pfctl_update_qstats(void) 1509 { 1510 struct pfctl_queue_node *node; 1511 struct pfioc_queue pq; 1512 struct pfioc_qstats pqs; 1513 u_int32_t mnr, nr; 1514 struct queue_stats qstats; 1515 static u_int32_t last_ticket; 1516 1517 memset(&pq, 0, sizeof(pq)); 1518 memset(&pqs, 0, sizeof(pqs)); 1519 memset(&qstats, 0, sizeof(qstats)); 1520 1521 if (pf_dev < 0) 1522 return (-1); 1523 1524 if (ioctl(pf_dev, DIOCGETQUEUES, &pq)) { 1525 error("DIOCGETQUEUES: %s", strerror(errno)); 1526 return (-1); 1527 } 1528 1529 /* if a new set is found, start over */ 1530 if (pq.ticket != last_ticket) 1531 while ((node = TAILQ_FIRST(&qnodes)) != NULL) { 1532 TAILQ_REMOVE(&qnodes, node, entries); 1533 free(node); 1534 } 1535 last_ticket = pq.ticket; 1536 1537 num_queues = mnr = pq.nr; 1538 for (nr = 0; nr < mnr; ++nr) { 1539 pqs.nr = nr; 1540 pqs.ticket = pq.ticket; 1541 pqs.buf = &qstats.data; 1542 pqs.nbytes = sizeof(qstats.data); 1543 if (ioctl(pf_dev, DIOCGETQSTATS, &pqs)) { 1544 error("DIOCGETQSTATS: %s", strerror(errno)); 1545 return (-1); 1546 } 1547 if (pqs.queue.qname[0] != '_') { 1548 if (pqs.queue.parent[0] && pqs.queue.parent[0] == '_') 1549 pqs.queue.parent[0] = '\0'; 1550 qstats.valid = 1; 1551 gettimeofday(&qstats.timestamp, NULL); 1552 if ((node = pfctl_find_queue_node(pqs.queue.qname, 1553 pqs.queue.ifname)) != NULL) { 1554 memcpy(&node->qstats_last, &node->qstats, 1555 sizeof(struct queue_stats)); 1556 memcpy(&node->qstats, &qstats, 1557 sizeof(struct queue_stats)); 1558 } else { 1559 pfctl_insert_queue_node(pqs.queue, qstats); 1560 } 1561 } else 1562 num_queues--; 1563 } 1564 return (0); 1565 } 1566 1567 int 1568 select_queues(void) 1569 { 1570 num_disp = num_queues; 1571 return (0); 1572 } 1573 1574 int 1575 read_queues(void) 1576 { 1577 num_disp = num_queues = 0; 1578 1579 if (pfctl_update_qstats() < 0) 1580 return (-1); 1581 num_disp = num_queues; 1582 1583 return(0); 1584 } 1585 1586 double 1587 calc_interval(struct timeval *cur_time, struct timeval *last_time) 1588 { 1589 double sec; 1590 1591 sec = (double)(cur_time->tv_sec - last_time->tv_sec) + 1592 (double)(cur_time->tv_usec - last_time->tv_usec) / 1000000; 1593 1594 return (sec); 1595 } 1596 1597 double 1598 calc_rate(u_int64_t new_bytes, u_int64_t last_bytes, double interval) 1599 { 1600 double rate; 1601 1602 rate = (double)(new_bytes - last_bytes) / interval; 1603 return (rate); 1604 } 1605 1606 double 1607 calc_pps(u_int64_t new_pkts, u_int64_t last_pkts, double interval) 1608 { 1609 double pps; 1610 1611 pps = (double)(new_pkts - last_pkts) / interval; 1612 return (pps); 1613 } 1614 1615 void 1616 print_queue_node(struct pfctl_queue_node *node) 1617 { 1618 u_int rate; 1619 int i; 1620 double interval, pps, bps; 1621 static const char unit[] = " KMG"; 1622 1623 tb_start(); 1624 for (i = 0; i < node->depth; i++) 1625 tbprintf(" "); 1626 tbprintf("%s", node->qs.qname); 1627 if (i == 0 && node->qs.ifname[0]) 1628 tbprintf(" on %s ", node->qs.ifname); 1629 print_fld_tb(FLD_QUEUE); 1630 1631 // XXX: missing min, max, burst 1632 tb_start(); 1633 rate = node->qs.linkshare.m2.absolute; 1634 for (i = 0; rate >= 1000 && i <= 3; i++) 1635 rate /= 1000; 1636 tbprintf("%u%c", rate, unit[i]); 1637 print_fld_tb(FLD_BANDW); 1638 1639 if (node->qstats.valid && node->qstats_last.valid) 1640 interval = calc_interval(&node->qstats.timestamp, 1641 &node->qstats_last.timestamp); 1642 else 1643 interval = 0; 1644 1645 print_fld_size(FLD_PKTS, node->qstats.data.xmit_cnt.packets); 1646 print_fld_size(FLD_BYTES, node->qstats.data.xmit_cnt.bytes); 1647 print_fld_size(FLD_DROPP, node->qstats.data.drop_cnt.packets); 1648 print_fld_size(FLD_DROPB, node->qstats.data.drop_cnt.bytes); 1649 print_fld_size(FLD_QLEN, node->qstats.data.qlength); 1650 1651 if (interval > 0) { 1652 pps = calc_pps(node->qstats.data.xmit_cnt.packets, 1653 node->qstats_last.data.xmit_cnt.packets, interval); 1654 bps = calc_rate(node->qstats.data.xmit_cnt.bytes, 1655 node->qstats_last.data.xmit_cnt.bytes, interval); 1656 1657 tb_start(); 1658 if (pps > 0 && pps < 1) 1659 tbprintf("%-3.1lf", pps); 1660 else 1661 tbprintf("%u", (unsigned int)pps); 1662 1663 print_fld_tb(FLD_PKTSPS); 1664 print_fld_bw(FLD_BYTESPS, bps); 1665 } 1666 } 1667 1668 void 1669 print_queues(void) 1670 { 1671 uint32_t n, count, start; 1672 struct pfctl_queue_node *node; 1673 1674 n = count = 0; 1675 start = dispstart; 1676 1677 TAILQ_FOREACH(node, &qnodes, entries) { 1678 if (n < start) { 1679 n++; 1680 continue; 1681 } 1682 print_queue_node(node); 1683 end_line(); 1684 count++; 1685 if (maxprint > 0 && count >= maxprint) 1686 return; 1687 } 1688 } 1689 1690 /* main program functions */ 1691 1692 void 1693 update_cache(void) 1694 { 1695 static int pstate = -1; 1696 if (pstate == cachestates) 1697 return; 1698 1699 pstate = cachestates; 1700 if (cachestates) { 1701 show_field(FLD_SI); 1702 show_field(FLD_SP); 1703 gotsig_alarm = 1; 1704 } else { 1705 hide_field(FLD_SI); 1706 hide_field(FLD_SP); 1707 need_update = 1; 1708 } 1709 field_setup(); 1710 } 1711 1712 int 1713 initpftop(void) 1714 { 1715 struct pf_status status; 1716 field_view *v; 1717 int cachesize = DEFAULT_CACHE_SIZE; 1718 1719 v = views; 1720 while(v->name != NULL) 1721 add_view(v++); 1722 1723 pf_dev = open("/dev/pf", O_RDONLY); 1724 if (pf_dev == -1) { 1725 alloc_buf(0); 1726 } else if (ioctl(pf_dev, DIOCGETSTATUS, &status)) { 1727 warn("DIOCGETSTATUS"); 1728 alloc_buf(0); 1729 } else 1730 alloc_buf(status.states); 1731 1732 /* initialize cache with given size */ 1733 if (cache_init(cachesize)) 1734 warnx("Failed to initialize cache."); 1735 else if (interactive && cachesize > 0) 1736 cachestates = 1; 1737 1738 update_cache(); 1739 1740 show_field(FLD_STMAX); 1741 show_field(FLD_ANCHOR); 1742 1743 return (1); 1744 } 1745