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