1 /* $OpenBSD: pftop.c,v 1.28 2014/05/09 21:03:43 sthen 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 <stdarg.h> 58 59 #include "systat.h" 60 #include "engine.h" 61 #include "cache.h" 62 63 extern const char *tcpstates[]; 64 65 #define MIN_NUM_STATES 1024 66 #define NUM_STATE_INC 1024 67 68 #define DEFAULT_CACHE_SIZE 10000 69 70 /* XXX must also check type before use */ 71 #define PT_ADDR(x) (&(x)->addr.v.a.addr) 72 73 /* XXX must also check type before use */ 74 #define PT_MASK(x) (&(x)->addr.v.a.mask) 75 76 #define PT_NOROUTE(x) ((x)->addr.type == PF_ADDR_NOROUTE) 77 78 /* view management */ 79 int select_states(void); 80 int read_states(void); 81 void sort_states(void); 82 void print_states(void); 83 84 int select_rules(void); 85 int read_rules(void); 86 void print_rules(void); 87 88 int select_queues(void); 89 int read_queues(void); 90 void print_queues(void); 91 92 void update_cache(void); 93 94 /* qsort callbacks */ 95 int sort_size_callback(const void *s1, const void *s2); 96 int sort_exp_callback(const void *s1, const void *s2); 97 int sort_pkt_callback(const void *s1, const void *s2); 98 int sort_age_callback(const void *s1, const void *s2); 99 int sort_sa_callback(const void *s1, const void *s2); 100 int sort_sp_callback(const void *s1, const void *s2); 101 int sort_da_callback(const void *s1, const void *s2); 102 int sort_dp_callback(const void *s1, const void *s2); 103 int sort_rate_callback(const void *s1, const void *s2); 104 int sort_peak_callback(const void *s1, const void *s2); 105 int pf_dev = -1; 106 107 struct sc_ent **state_cache = NULL; 108 struct pfsync_state *state_buf = NULL; 109 int state_buf_len = 0; 110 u_int32_t *state_ord = NULL; 111 u_int32_t num_states = 0; 112 u_int32_t num_states_all = 0; 113 u_int32_t num_rules = 0; 114 u_int32_t num_queues = 0; 115 int cachestates = 0; 116 117 char *filter_string = NULL; 118 int dumpfilter = 0; 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 = realloc(state_buf, len * sizeof(struct pfsync_state)); 640 state_ord = realloc(state_ord, len * sizeof(u_int32_t)); 641 state_cache = realloc(state_cache, 642 len * sizeof(struct sc_ent *)); 643 if (state_buf == NULL || state_ord == NULL || 644 state_cache == NULL) 645 err(1, "realloc"); 646 state_buf_len = len; 647 } 648 } 649 650 int 651 select_states(void) 652 { 653 num_disp = num_states; 654 return (0); 655 } 656 657 int 658 read_states(void) 659 { 660 struct pfioc_states ps; 661 int n; 662 663 if (pf_dev == -1) 664 return -1; 665 666 for (;;) { 667 int sbytes = state_buf_len * sizeof(struct pfsync_state); 668 669 ps.ps_len = sbytes; 670 ps.ps_buf = (char *) state_buf; 671 672 if (ioctl(pf_dev, DIOCGETSTATES, &ps) < 0) { 673 error("DIOCGETSTATES"); 674 } 675 num_states_all = ps.ps_len / sizeof(struct pfsync_state); 676 677 if (ps.ps_len < sbytes) 678 break; 679 680 alloc_buf(num_states_all); 681 } 682 683 if (dumpfilter) { 684 int fd = open("state.dmp", O_WRONLY|O_CREAT|O_EXCL, 0); 685 if (fd > 0) { 686 write(fd, state_buf, ps.ps_len); 687 close(fd); 688 } 689 } 690 691 num_states = num_states_all; 692 for (n = 0; n<num_states_all; n++) 693 state_ord[n] = n; 694 695 if (cachestates) { 696 for (n = 0; n < num_states; n++) 697 state_cache[n] = cache_state(state_buf + n); 698 cache_endupdate(); 699 } 700 701 num_disp = num_states; 702 return 0; 703 } 704 705 int 706 unmask(struct pf_addr * m, u_int8_t af) 707 { 708 int i = 31, j = 0, b = 0, msize; 709 u_int32_t tmp; 710 711 if (af == AF_INET) 712 msize = 1; 713 else 714 msize = 4; 715 while (j < msize && m->addr32[j] == 0xffffffff) { 716 b += 32; 717 j++; 718 } 719 if (j < msize) { 720 tmp = ntohl(m->addr32[j]); 721 for (i = 31; tmp & (1 << i); --i) 722 b++; 723 } 724 return (b); 725 } 726 727 /* display functions */ 728 729 void 730 tb_print_addr(struct pf_addr * addr, struct pf_addr * mask, int af) 731 { 732 switch (af) { 733 case AF_INET: { 734 tbprintf("%s", inetname(addr->v4)); 735 break; 736 } 737 case AF_INET6: { 738 tbprintf("%s", inet6name(&addr->v6)); 739 break; 740 } 741 } 742 743 if (mask != NULL) { 744 if (!PF_AZERO(mask, af)) 745 tbprintf("/%u", unmask(mask, af)); 746 } 747 } 748 749 void 750 print_fld_host2(field_def *fld, struct pfsync_state_key *ks, 751 struct pfsync_state_key *kn, int idx) 752 { 753 struct pf_addr *as = &ks->addr[idx]; 754 struct pf_addr *an = &kn->addr[idx]; 755 756 u_int16_t ps = ntohs(ks->port[idx]); 757 u_int16_t pn = ntohs(kn->port[idx]); 758 759 int asf = ks->af; 760 int anf = kn->af; 761 762 if (fld == NULL) 763 return; 764 765 if (fld->width < 3) { 766 print_fld_str(fld, "*"); 767 return; 768 } 769 770 tb_start(); 771 tb_print_addr(as, NULL, asf); 772 773 if (asf == AF_INET) 774 tbprintf(":%u", ps); 775 else 776 tbprintf("[%u]", ps); 777 778 print_fld_tb(fld); 779 780 if (asf != anf || PF_ANEQ(as, an, asf) || ps != pn) { 781 tb_start(); 782 tb_print_addr(an, NULL, anf); 783 784 if (anf == AF_INET) 785 tbprintf(":%u", pn); 786 else 787 tbprintf("[%u]", pn); 788 print_fld_tb(FLD_GW); 789 } 790 791 } 792 793 void 794 print_fld_state(field_def *fld, unsigned int proto, 795 unsigned int s1, unsigned int s2) 796 { 797 int len; 798 799 if (fld == NULL) 800 return; 801 802 len = fld->width; 803 if (len < 1) 804 return; 805 806 tb_start(); 807 808 if (proto == IPPROTO_TCP) { 809 if (s1 <= TCPS_TIME_WAIT && s2 <= TCPS_TIME_WAIT) 810 tbprintf("%s:%s", tcpstates[s1], tcpstates[s2]); 811 #ifdef PF_TCPS_PROXY_SRC 812 else if (s1 == PF_TCPS_PROXY_SRC || 813 s2 == PF_TCPS_PROXY_SRC) 814 tbprintf("PROXY:SRC\n"); 815 else if (s1 == PF_TCPS_PROXY_DST || 816 s2 == PF_TCPS_PROXY_DST) 817 tbprintf("PROXY:DST\n"); 818 #endif 819 else 820 tbprintf("<BAD STATE LEVELS>"); 821 } else if (proto == IPPROTO_UDP && s1 < PFUDPS_NSTATES && 822 s2 < PFUDPS_NSTATES) { 823 const char *states[] = PFUDPS_NAMES; 824 tbprintf("%s:%s", states[s1], states[s2]); 825 } else if (proto != IPPROTO_ICMP && s1 < PFOTHERS_NSTATES && 826 s2 < PFOTHERS_NSTATES) { 827 /* XXX ICMP doesn't really have state levels */ 828 const char *states[] = PFOTHERS_NAMES; 829 tbprintf("%s:%s", states[s1], states[s2]); 830 } else { 831 tbprintf("%u:%u", s1, s2); 832 } 833 834 if (strlen(tmp_buf) > len) { 835 tb_start(); 836 tbprintf("%u:%u", s1, s2); 837 } 838 839 print_fld_tb(fld); 840 } 841 842 int 843 print_state(struct pfsync_state * s, struct sc_ent * ent) 844 { 845 struct pfsync_state_peer *src, *dst; 846 struct protoent *p; 847 u_int64_t sz; 848 int afto, dir; 849 850 afto = s->key[PF_SK_STACK].af == s->key[PF_SK_WIRE].af ? 0 : 1; 851 dir = afto ? PF_OUT : s->direction; 852 853 if (dir == PF_OUT) { 854 src = &s->src; 855 dst = &s->dst; 856 } else { 857 src = &s->dst; 858 dst = &s->src; 859 } 860 861 p = getprotobynumber(s->proto); 862 863 if (p != NULL) 864 print_fld_str(FLD_PROTO, p->p_name); 865 else 866 print_fld_uint(FLD_PROTO, s->proto); 867 868 if (dir == PF_OUT) { 869 print_fld_host2(FLD_SRC, 870 &s->key[afto ? PF_SK_STACK : PF_SK_WIRE], 871 &s->key[PF_SK_STACK], 1); 872 print_fld_host2(FLD_DEST, 873 &s->key[afto ? PF_SK_STACK : PF_SK_WIRE], 874 &s->key[afto ? PF_SK_WIRE : PF_SK_STACK], 0); 875 } else { 876 print_fld_host2(FLD_SRC, &s->key[PF_SK_STACK], 877 &s->key[PF_SK_WIRE], 0); 878 print_fld_host2(FLD_DEST, &s->key[PF_SK_STACK], 879 &s->key[PF_SK_WIRE], 1); 880 } 881 882 if (dir == PF_OUT) 883 print_fld_str(FLD_DIR, "Out"); 884 else 885 print_fld_str(FLD_DIR, "In"); 886 887 print_fld_state(FLD_STATE, s->proto, src->state, dst->state); 888 print_fld_age(FLD_AGE, ntohl(s->creation)); 889 print_fld_age(FLD_EXP, ntohl(s->expire)); 890 891 sz = COUNTER(s->bytes[0]) + COUNTER(s->bytes[1]); 892 893 print_fld_size(FLD_PKTS, COUNTER(s->packets[0]) + 894 COUNTER(s->packets[1])); 895 print_fld_size(FLD_BYTES, sz); 896 print_fld_rate(FLD_SA, (s->creation) ? 897 ((double)sz/ntohl((double)s->creation)) : -1); 898 899 print_fld_uint(FLD_RULE, ntohl(s->rule)); 900 if (cachestates && ent != NULL) { 901 print_fld_rate(FLD_SI, ent->rate); 902 print_fld_rate(FLD_SP, ent->peak); 903 } 904 905 end_line(); 906 return 1; 907 } 908 909 void 910 print_states(void) 911 { 912 int n, count = 0; 913 914 for (n = dispstart; n < num_disp; n++) { 915 count += print_state(state_buf + state_ord[n], 916 state_cache[state_ord[n]]); 917 if (maxprint > 0 && count >= maxprint) 918 break; 919 } 920 } 921 922 /* rule display */ 923 924 struct pf_rule *rules = NULL; 925 u_int32_t alloc_rules = 0; 926 927 int 928 select_rules(void) 929 { 930 num_disp = num_rules; 931 return (0); 932 } 933 934 935 void 936 add_rule_alloc(u_int32_t nr) 937 { 938 if (nr == 0) 939 return; 940 941 num_rules += nr; 942 943 if (rules == NULL) { 944 rules = malloc(num_rules * sizeof(struct pf_rule)); 945 if (rules == NULL) 946 err(1, "malloc"); 947 alloc_rules = num_rules; 948 } else if (num_rules > alloc_rules) { 949 rules = realloc(rules, num_rules * sizeof(struct pf_rule)); 950 if (rules == NULL) 951 err(1, "realloc"); 952 alloc_rules = num_rules; 953 } 954 } 955 956 int label_length; 957 958 int 959 read_anchor_rules(char *anchor) 960 { 961 struct pfioc_rule pr; 962 u_int32_t nr, num, off; 963 int len; 964 965 if (pf_dev < 0) 966 return (-1); 967 968 memset(&pr, 0, sizeof(pr)); 969 strlcpy(pr.anchor, anchor, sizeof(pr.anchor)); 970 971 if (ioctl(pf_dev, DIOCGETRULES, &pr)) { 972 error("anchor %s: %s", anchor, strerror(errno)); 973 return (-1); 974 } 975 976 off = num_rules; 977 num = pr.nr; 978 add_rule_alloc(num); 979 980 for (nr = 0; nr < num; ++nr) { 981 pr.nr = nr; 982 if (ioctl(pf_dev, DIOCGETRULE, &pr)) { 983 error("DIOCGETRULE: %s", strerror(errno)); 984 return (-1); 985 } 986 /* XXX overload pr.anchor, to store a pointer to 987 * anchor name */ 988 pr.rule.anchor = (struct pf_anchor *) anchor; 989 len = strlen(pr.rule.label); 990 if (len > label_length) 991 label_length = len; 992 rules[off + nr] = pr.rule; 993 } 994 995 return (num); 996 } 997 998 struct anchor_name { 999 char name[MAXPATHLEN]; 1000 struct anchor_name *next; 1001 u_int32_t ref; 1002 }; 1003 1004 struct anchor_name *anchor_root = NULL; 1005 struct anchor_name *anchor_end = NULL; 1006 struct anchor_name *anchor_free = NULL; 1007 1008 struct anchor_name* 1009 alloc_anchor_name(const char *path) 1010 { 1011 struct anchor_name *a; 1012 1013 a = anchor_free; 1014 if (a == NULL) { 1015 a = (struct anchor_name *)malloc(sizeof(struct anchor_name)); 1016 if (a == NULL) 1017 return (NULL); 1018 } else 1019 anchor_free = a->next; 1020 1021 if (anchor_root == NULL) 1022 anchor_end = a; 1023 1024 a->next = anchor_root; 1025 anchor_root = a; 1026 1027 a->ref = 0; 1028 strlcpy(a->name, path, sizeof(a->name)); 1029 return (a); 1030 } 1031 1032 void 1033 reset_anchor_names(void) 1034 { 1035 if (anchor_end == NULL) 1036 return; 1037 1038 anchor_end->next = anchor_free; 1039 anchor_free = anchor_root; 1040 anchor_root = anchor_end = NULL; 1041 } 1042 1043 struct pfioc_ruleset ruleset; 1044 char *rs_end = NULL; 1045 1046 int 1047 read_rulesets(const char *path) 1048 { 1049 char *pre; 1050 struct anchor_name *a; 1051 u_int32_t nr, ns; 1052 int len; 1053 1054 if (path == NULL) 1055 ruleset.path[0] = '\0'; 1056 else if (strlcpy(ruleset.path, path, sizeof(ruleset.path)) >= 1057 sizeof(ruleset.path)) 1058 return (-1); 1059 1060 /* a persistent storage for anchor names */ 1061 a = alloc_anchor_name(ruleset.path); 1062 if (a == NULL) 1063 return (-1); 1064 1065 len = read_anchor_rules(a->name); 1066 if (len < 0) 1067 return (-1); 1068 1069 a->ref += len; 1070 1071 if (ioctl(pf_dev, DIOCGETRULESETS, &ruleset)) { 1072 error("DIOCGETRULESETS: %s", strerror(errno)); 1073 return (-1); 1074 } 1075 1076 ns = ruleset.nr; 1077 1078 if (rs_end == NULL) 1079 rs_end = ruleset.path + sizeof(ruleset.path); 1080 1081 /* 'pre' tracks the previous level on the anchor */ 1082 pre = strchr(ruleset.path, 0); 1083 len = rs_end - pre; 1084 if (len < 1) 1085 return (-1); 1086 --len; 1087 1088 for (nr = 0; nr < ns; ++nr) { 1089 ruleset.nr = nr; 1090 if (ioctl(pf_dev, DIOCGETRULESET, &ruleset)) { 1091 error("DIOCGETRULESET: %s", strerror(errno)); 1092 return (-1); 1093 } 1094 *pre = '/'; 1095 if (strlcpy(pre + 1, ruleset.name, len) < len) 1096 read_rulesets(ruleset.path); 1097 *pre = '\0'; 1098 } 1099 1100 return (0); 1101 } 1102 1103 void 1104 compute_anchor_field(void) 1105 { 1106 struct anchor_name *a; 1107 int sum, cnt, mx, nx; 1108 sum = cnt = mx = 0; 1109 1110 for (a = anchor_root; a != NULL; a = a->next, cnt++) { 1111 int len; 1112 if (a->ref == 0) 1113 continue; 1114 len = strlen(a->name); 1115 sum += len; 1116 if (len > mx) 1117 mx = len; 1118 } 1119 1120 nx = sum/cnt; 1121 if (nx < ANCHOR_FLD_SIZE) 1122 nx = (mx < ANCHOR_FLD_SIZE) ? mx : ANCHOR_FLD_SIZE; 1123 1124 if (FLD_ANCHOR->max_width != mx || 1125 FLD_ANCHOR->norm_width != nx) { 1126 FLD_ANCHOR->max_width = mx; 1127 FLD_ANCHOR->norm_width = nx; 1128 field_setup(); 1129 need_update = 1; 1130 } 1131 } 1132 1133 int 1134 read_rules(void) 1135 { 1136 int ret, nw, mw; 1137 num_rules = 0; 1138 1139 if (pf_dev == -1) 1140 return (-1); 1141 1142 label_length = MIN_LABEL_SIZE; 1143 1144 reset_anchor_names(); 1145 ret = read_rulesets(NULL); 1146 compute_anchor_field(); 1147 1148 nw = mw = label_length; 1149 if (nw > 16) 1150 nw = 16; 1151 1152 if (FLD_LABEL->norm_width != nw || 1153 FLD_LABEL->max_width != mw) { 1154 FLD_LABEL->norm_width = nw; 1155 FLD_LABEL->max_width = mw; 1156 field_setup(); 1157 need_update = 1; 1158 } 1159 1160 num_disp = num_rules; 1161 return (ret); 1162 } 1163 1164 void 1165 tb_print_addrw(struct pf_addr_wrap *addr, struct pf_addr *mask, u_int8_t af) 1166 { 1167 switch (addr->type) { 1168 case PF_ADDR_ADDRMASK: 1169 tb_print_addr(&addr->v.a.addr, mask, af); 1170 break; 1171 case PF_ADDR_NOROUTE: 1172 tbprintf("noroute"); 1173 break; 1174 case PF_ADDR_DYNIFTL: 1175 tbprintf("(%s)", addr->v.ifname); 1176 break; 1177 case PF_ADDR_TABLE: 1178 tbprintf("<%s>", addr->v.tblname); 1179 break; 1180 default: 1181 tbprintf("UNKNOWN"); 1182 break; 1183 } 1184 } 1185 1186 void 1187 tb_print_op(u_int8_t op, const char *a1, const char *a2) 1188 { 1189 if (op == PF_OP_IRG) 1190 tbprintf("%s >< %s ", a1, a2); 1191 else if (op == PF_OP_XRG) 1192 tbprintf("%s <> %s ", a1, a2); 1193 else if (op == PF_OP_RRG) 1194 tbprintf("%s:%s ", a1, a2); 1195 else if (op == PF_OP_EQ) 1196 tbprintf("= %s ", a1); 1197 else if (op == PF_OP_NE) 1198 tbprintf("!= %s ", a1); 1199 else if (op == PF_OP_LT) 1200 tbprintf("< %s ", a1); 1201 else if (op == PF_OP_LE) 1202 tbprintf("<= %s ", a1); 1203 else if (op == PF_OP_GT) 1204 tbprintf("> %s ", a1); 1205 else if (op == PF_OP_GE) 1206 tbprintf(">= %s ", a1); 1207 } 1208 1209 void 1210 tb_print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto) 1211 { 1212 char a1[6], a2[6]; 1213 struct servent *s = getservbyport(p1, proto); 1214 1215 p1 = ntohs(p1); 1216 p2 = ntohs(p2); 1217 snprintf(a1, sizeof(a1), "%u", p1); 1218 snprintf(a2, sizeof(a2), "%u", p2); 1219 tbprintf("port "); 1220 if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) 1221 tb_print_op(op, s->s_name, a2); 1222 else 1223 tb_print_op(op, a1, a2); 1224 } 1225 1226 void 1227 tb_print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst, 1228 u_int8_t af, u_int8_t proto) 1229 { 1230 if ( 1231 PF_AZERO(PT_ADDR(src), AF_INET6) && 1232 PF_AZERO(PT_ADDR(dst), AF_INET6) && 1233 ! PT_NOROUTE(src) && ! PT_NOROUTE(dst) && 1234 PF_AZERO(PT_MASK(src), AF_INET6) && 1235 PF_AZERO(PT_MASK(dst), AF_INET6) && 1236 !src->port_op && !dst->port_op) 1237 tbprintf("all "); 1238 else { 1239 tbprintf("from "); 1240 if (PT_NOROUTE(src)) 1241 tbprintf("no-route "); 1242 else if (PF_AZERO(PT_ADDR(src), AF_INET6) && 1243 PF_AZERO(PT_MASK(src), AF_INET6)) 1244 tbprintf("any "); 1245 else { 1246 if (src->neg) 1247 tbprintf("! "); 1248 tb_print_addrw(&src->addr, PT_MASK(src), af); 1249 tbprintf(" "); 1250 } 1251 if (src->port_op) 1252 tb_print_port(src->port_op, src->port[0], 1253 src->port[1], 1254 proto == IPPROTO_TCP ? "tcp" : "udp"); 1255 1256 tbprintf("to "); 1257 if (PT_NOROUTE(dst)) 1258 tbprintf("no-route "); 1259 else if (PF_AZERO(PT_ADDR(dst), AF_INET6) && 1260 PF_AZERO(PT_MASK(dst), AF_INET6)) 1261 tbprintf("any "); 1262 else { 1263 if (dst->neg) 1264 tbprintf("! "); 1265 tb_print_addrw(&dst->addr, PT_MASK(dst), af); 1266 tbprintf(" "); 1267 } 1268 if (dst->port_op) 1269 tb_print_port(dst->port_op, dst->port[0], 1270 dst->port[1], 1271 proto == IPPROTO_TCP ? "tcp" : "udp"); 1272 } 1273 } 1274 1275 void 1276 tb_print_ugid(u_int8_t op, unsigned u1, unsigned u2, 1277 const char *t, unsigned umax) 1278 { 1279 char a1[11], a2[11]; 1280 1281 snprintf(a1, sizeof(a1), "%u", u1); 1282 snprintf(a2, sizeof(a2), "%u", u2); 1283 1284 tbprintf("%s ", t); 1285 if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) 1286 tb_print_op(op, "unknown", a2); 1287 else 1288 tb_print_op(op, a1, a2); 1289 } 1290 1291 void 1292 tb_print_flags(u_int8_t f) 1293 { 1294 const char *tcpflags = "FSRPAUEW"; 1295 int i; 1296 1297 for (i = 0; tcpflags[i]; ++i) 1298 if (f & (1 << i)) 1299 tbprintf("%c", tcpflags[i]); 1300 } 1301 1302 void 1303 print_rule(struct pf_rule *pr) 1304 { 1305 static const char *actiontypes[] = { "Pass", "Block", "Scrub", 1306 "no Scrub", "Nat", "no Nat", "Binat", "no Binat", "Rdr", 1307 "no Rdr", "SynProxy Block", "Defer", "Match" }; 1308 int numact = sizeof(actiontypes) / sizeof(char *); 1309 1310 static const char *routetypes[] = { "", "fastroute", "route-to", 1311 "dup-to", "reply-to" }; 1312 1313 int numroute = sizeof(routetypes) / sizeof(char *); 1314 1315 if (pr == NULL) return; 1316 1317 print_fld_str(FLD_LABEL, pr->label); 1318 print_fld_size(FLD_STATS, pr->states_tot); 1319 1320 print_fld_size(FLD_PKTS, pr->packets[0] + pr->packets[1]); 1321 print_fld_size(FLD_BYTES, pr->bytes[0] + pr->bytes[1]); 1322 1323 print_fld_uint(FLD_RULE, pr->nr); 1324 if (pr->direction == PF_OUT) 1325 print_fld_str(FLD_DIR, "Out"); 1326 else if (pr->direction == PF_IN) 1327 print_fld_str(FLD_DIR, "In"); 1328 else 1329 print_fld_str(FLD_DIR, "Any"); 1330 1331 if (pr->quick) 1332 print_fld_str(FLD_QUICK, "Quick"); 1333 1334 if (pr->keep_state == PF_STATE_NORMAL) 1335 print_fld_str(FLD_KST, "Keep"); 1336 else if (pr->keep_state == PF_STATE_MODULATE) 1337 print_fld_str(FLD_KST, "Mod"); 1338 #ifdef PF_STATE_SYNPROXY 1339 else if (pr->keep_state == PF_STATE_MODULATE) 1340 print_fld_str(FLD_KST, "Syn"); 1341 #endif 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