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