[BACK]Return to pftop.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / systat

Annotation of src/usr.bin/systat/pftop.c, Revision 1.47

1.47    ! jsg         1: /* $OpenBSD: pftop.c,v 1.46 2023/07/04 11:34:19 sashan Exp $    */
1.1       canacar     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>
1.8       mcbride    39: #include <netinet/tcp.h>
1.1       canacar    40: #include <netinet/tcp_fsm.h>
                     41: #include <net/pfvar.h>
                     42: #include <arpa/inet.h>
                     43:
1.22      henning    44: #include <net/hfsc.h>
                     45:
1.1       canacar    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>
1.30      deraadt    57: #include <limits.h>
1.1       canacar    58: #include <stdarg.h>
                     59:
1.6       canacar    60: #include "systat.h"
1.1       canacar    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:
1.7       canacar    93: void update_cache(void);
                     94:
1.1       canacar    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;
1.4       canacar   109: struct pfsync_state *state_buf = NULL;
1.43      bluhm     110: size_t state_buf_len = 0;
                    111: size_t *state_ord = NULL;
                    112: size_t num_states = 0;
                    113: size_t num_states_all = 0;
1.1       canacar   114: u_int32_t num_rules = 0;
                    115: u_int32_t num_queues = 0;
                    116: int cachestates = 0;
                    117:
                    118: char *filter_string = NULL;
                    119:
                    120: #define MIN_LABEL_SIZE 5
                    121: #define ANCHOR_FLD_SIZE 12
                    122:
                    123: /* Define fields */
                    124: field_def fields[] = {
                    125:        {"SRC", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    126:        {"DEST", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    127:        {"GW", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    128:        {"STATE", 5, 23, 18, FLD_ALIGN_COLUMN, -1, 0, 0, 0},
                    129:        {"AGE", 5, 9, 4, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    130:        {"EXP", 5, 9, 4, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    131:        {"PR ", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    132:        {"DIR", 1, 3, 2, FLD_ALIGN_CENTER, -1, 0, 0, 0},
                    133:        {"PKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    134:        {"BYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    135:        {"RULE", 2, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    136:        {"LABEL", MIN_LABEL_SIZE, MIN_LABEL_SIZE, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    137:        {"STATES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    138:        {"EVAL", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    139:        {"ACTION", 1, 8, 4, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    140:        {"LOG", 1, 3, 2, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    141:        {"QUICK", 1, 1, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    142:        {"KS", 1, 1, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.35      jasper    143:        {"IF", 4, 7, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.1       canacar   144:        {"INFO", 40, 80, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.4       canacar   145:        {"MAX", 3, 5, 2, FLD_ALIGN_RIGHT, -1, 0, 0},
1.1       canacar   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},
1.4       canacar   149:        {"ANCHOR", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0},
1.1       canacar   150:        {"QUEUE", 15, 30, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1.39      mikeb     151:        {"BW/FL", 4, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
1.1       canacar   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 */
1.18      jasper    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)
1.1       canacar   170: /* common */
1.18      jasper    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)
1.1       canacar   176: /* for rules */
1.18      jasper    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)
1.1       canacar   187: /* other */
1.18      jasper    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)
1.1       canacar   192: /* for queues */
1.18      jasper    193: #define FLD_QUEUE   FIELD_ADDR(fields,25)
                    194: #define FLD_BANDW   FIELD_ADDR(fields,26)
                    195: #define FLD_SCHED   FIELD_ADDR(fields,27)
1.37      mikeb     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)
1.1       canacar   203:
                    204: /* Define views */
                    205: field_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:
                    210: field_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:
                    215: field_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:
                    220: field_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:
                    225: field_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:
                    230: field_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:
                    236: field_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:
                    242: field_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:
                    247: field_def *view8[] = {
1.37      mikeb     248:        FLD_QUEUE, FLD_BANDW, FLD_SCHED, FLD_PKTS, FLD_BYTES,
1.1       canacar   249:        FLD_DROPP, FLD_DROPB, FLD_QLEN, FLD_BORR, FLD_SUSP, FLD_PKTSPS,
                    250:        FLD_BYTESPS, NULL
                    251: };
                    252:
                    253: /* Define orderings */
                    254: order_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 */
                    270: struct view_manager state_mgr = {
                    271:        "States", select_states, read_states, sort_states, print_header,
1.41      martijn   272:        print_states, keyboard_callback, order_list, order_list
1.1       canacar   273: };
                    274:
                    275: struct view_manager rule_mgr = {
                    276:        "Rules", select_rules, read_rules, NULL, print_header,
                    277:        print_rules, keyboard_callback, NULL, NULL
                    278: };
                    279:
                    280: struct view_manager queue_mgr = {
                    281:        "Queues", select_queues, read_queues, NULL, print_header,
                    282:        print_queues, keyboard_callback, NULL, NULL
                    283: };
                    284:
                    285: field_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:
1.22      henning   292: /* queue structures from pfctl */
                    293:
                    294: struct queue_stats {
                    295:        struct hfsc_class_stats  data;
                    296:        int                      valid;
                    297:        struct timeval           timestamp;
                    298: };
                    299:
                    300: struct 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: };
                    307: TAILQ_HEAD(qnodes, pfctl_queue_node) qnodes = TAILQ_HEAD_INITIALIZER(qnodes);
1.1       canacar   308:
                    309: /* ordering functions */
                    310:
                    311: int
                    312: sort_size_callback(const void *s1, const void *s2)
                    313: {
1.43      bluhm     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]);
1.1       canacar   318:        if (b2 > b1)
                    319:                return sortdir;
                    320:        if (b2 < b1)
                    321:                return -sortdir;
                    322:        return 0;
                    323: }
                    324:
                    325: int
                    326: sort_pkt_callback(const void *s1, const void *s2)
                    327: {
1.43      bluhm     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]);
1.1       canacar   332:        if (p2 > p1)
                    333:                return sortdir;
                    334:        if (p2 < p1)
                    335:                return -sortdir;
                    336:        return 0;
                    337: }
                    338:
                    339: int
                    340: sort_age_callback(const void *s1, const void *s2)
                    341: {
1.43      bluhm     342:        if (ntohl(state_buf[* (size_t *) s2].creation) >
                    343:            ntohl(state_buf[* (size_t *) s1].creation))
1.1       canacar   344:                return sortdir;
1.43      bluhm     345:        if (ntohl(state_buf[* (size_t *) s2].creation) <
                    346:            ntohl(state_buf[* (size_t *) s1].creation))
1.1       canacar   347:                return -sortdir;
                    348:        return 0;
                    349: }
                    350:
                    351: int
                    352: sort_exp_callback(const void *s1, const void *s2)
                    353: {
1.43      bluhm     354:        if (ntohl(state_buf[* (size_t *) s2].expire) >
                    355:            ntohl(state_buf[* (size_t *) s1].expire))
1.1       canacar   356:                return sortdir;
1.43      bluhm     357:        if (ntohl(state_buf[* (size_t *) s2].expire) <
                    358:            ntohl(state_buf[* (size_t *) s1].expire))
1.1       canacar   359:                return -sortdir;
                    360:        return 0;
                    361: }
                    362:
                    363: int
                    364: sort_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;
1.26      sthen     373:
1.1       canacar   374:        if (e2->rate > e1 -> rate)
                    375:                return sortdir;
                    376:        if (e2->rate < e1 -> rate)
                    377:                return -sortdir;
                    378:        return 0;
                    379: }
                    380:
                    381: int
                    382: sort_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;
1.26      sthen     391:
1.1       canacar   392:        if (e2->peak > e1 -> peak)
                    393:                return sortdir;
                    394:        if (e2->peak < e1 -> peak)
                    395:                return -sortdir;
                    396:        return 0;
                    397: }
                    398:
                    399: int
                    400: compare_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:        }
1.26      sthen     428:
1.1       canacar   429:        return 0;
                    430: }
                    431:
1.13      jsg       432: static __inline int
1.4       canacar   433: sort_addr_callback(const struct pfsync_state *s1,
                    434:                   const struct pfsync_state *s2, int dir)
1.1       canacar   435: {
                    436:        const struct pf_addr *aa, *ab;
                    437:        u_int16_t pa, pb;
1.20      claudio   438:        int af, side, ret, ii, io;
1.1       canacar   439:
1.20      claudio   440:        side = s1->direction == PF_IN ? PF_SK_STACK : PF_SK_WIRE;
1.1       canacar   441:
1.20      claudio   442:        if (s1->key[side].af > s2->key[side].af)
1.1       canacar   443:                return sortdir;
1.20      claudio   444:        if (s1->key[side].af < s2->key[side].af)
1.1       canacar   445:                return -sortdir;
1.20      claudio   446:
1.26      sthen     447:        ii = io = 0;
1.1       canacar   448:
                    449:        if (dir == PF_OUT)      /* looking for source addr */
                    450:                io = 1;
                    451:        else                    /* looking for dest addr */
                    452:                ii = 1;
1.20      claudio   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) {
1.1       canacar   463:                aa = &s1->key[PF_SK_STACK].addr[ii];
                    464:                pa =  s1->key[PF_SK_STACK].port[ii];
1.20      claudio   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;
1.1       canacar   475:        } else {
1.20      claudio   476:                dir = s2->direction;
                    477:                side = PF_SK_WIRE;
1.1       canacar   478:        }
                    479:
1.20      claudio   480:        if (dir == PF_IN) {
1.16      deraadt   481:                ab = &s2->key[PF_SK_STACK].addr[ii];
1.1       canacar   482:                pb =  s2->key[PF_SK_STACK].port[ii];
1.20      claudio   483:                af = s1->key[PF_SK_STACK].af;
1.1       canacar   484:        } else {
1.20      claudio   485:                ab = &s2->key[side].addr[io];
                    486:                pb =  s2->key[side].port[io];
                    487:                af = s1->key[side].af;
1.1       canacar   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:
1.13      jsg       499: static __inline int
1.4       canacar   500: sort_port_callback(const struct pfsync_state *s1,
                    501:                   const struct pfsync_state *s2, int dir)
1.1       canacar   502: {
                    503:        const struct pf_addr *aa, *ab;
                    504:        u_int16_t pa, pb;
1.20      claudio   505:        int af, side, ret, ii, io;
1.1       canacar   506:
1.20      claudio   507:        side = s1->direction == PF_IN ? PF_SK_STACK : PF_SK_WIRE;
1.1       canacar   508:
1.20      claudio   509:        if (s1->key[side].af > s2->key[side].af)
1.1       canacar   510:                return sortdir;
1.20      claudio   511:        if (s1->key[side].af < s2->key[side].af)
1.1       canacar   512:                return -sortdir;
1.20      claudio   513:
1.26      sthen     514:        ii = io = 0;
1.1       canacar   515:
                    516:        if (dir == PF_OUT)      /* looking for source addr */
                    517:                io = 1;
                    518:        else                    /* looking for dest addr */
                    519:                ii = 1;
1.20      claudio   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) {
1.1       canacar   530:                aa = &s1->key[PF_SK_STACK].addr[ii];
                    531:                pa =  s1->key[PF_SK_STACK].port[ii];
1.20      claudio   532:                af = s1->key[PF_SK_STACK].af;
1.1       canacar   533:        } else {
1.20      claudio   534:                aa = &s1->key[side].addr[io];
                    535:                pa =  s1->key[side].port[io];
                    536:                af = s1->key[side].af;
1.1       canacar   537:        }
                    538:
1.20      claudio   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) {
1.16      deraadt   548:                ab = &s2->key[PF_SK_STACK].addr[ii];
1.1       canacar   549:                pb =  s2->key[PF_SK_STACK].port[ii];
1.20      claudio   550:                af = s1->key[PF_SK_STACK].af;
1.1       canacar   551:        } else {
1.20      claudio   552:                ab = &s2->key[side].addr[io];
                    553:                pb =  s2->key[side].port[io];
                    554:                af = s1->key[side].af;
1.1       canacar   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:
                    569: int
1.4       canacar   570: sort_sa_callback(const void *p1, const void *p2)
1.1       canacar   571: {
1.43      bluhm     572:        struct pfsync_state *s1 = state_buf + (* (size_t *) p1);
                    573:        struct pfsync_state *s2 = state_buf + (* (size_t *) p2);
1.4       canacar   574:        return sort_addr_callback(s1, s2, PF_OUT);
1.1       canacar   575: }
                    576:
                    577: int
1.4       canacar   578: sort_da_callback(const void *p1, const void *p2)
1.1       canacar   579: {
1.43      bluhm     580:        struct pfsync_state *s1 = state_buf + (* (size_t *) p1);
                    581:        struct pfsync_state *s2 = state_buf + (* (size_t *) p2);
1.1       canacar   582:        return sort_addr_callback(s1, s2, PF_IN);
                    583: }
                    584:
                    585: int
                    586: sort_sp_callback(const void *p1, const void *p2)
                    587: {
1.43      bluhm     588:        struct pfsync_state *s1 = state_buf + (* (size_t *) p1);
                    589:        struct pfsync_state *s2 = state_buf + (* (size_t *) p2);
1.1       canacar   590:        return sort_port_callback(s1, s2, PF_OUT);
                    591: }
                    592:
                    593: int
                    594: sort_dp_callback(const void *p1, const void *p2)
                    595: {
1.43      bluhm     596:        struct pfsync_state *s1 = state_buf + (* (size_t *) p1);
                    597:        struct pfsync_state *s2 = state_buf + (* (size_t *) p2);
1.1       canacar   598:        return sort_port_callback(s1, s2, PF_IN);
                    599: }
                    600:
                    601: void
                    602: sort_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:
1.43      bluhm     620:        mergesort(state_ord, num_states, sizeof(size_t), ordering->func);
1.1       canacar   621: }
                    622:
                    623: /* state management functions */
                    624:
                    625: void
1.43      bluhm     626: alloc_buf(size_t ns)
1.1       canacar   627: {
1.43      bluhm     628:        size_t len;
1.1       canacar   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;
1.29      doug      637:                state_buf = reallocarray(state_buf, len,
                    638:                    sizeof(struct pfsync_state));
1.43      bluhm     639:                state_ord = reallocarray(state_ord, len, sizeof(size_t));
1.29      doug      640:                state_cache = reallocarray(state_cache, len,
                    641:                    sizeof(struct sc_ent *));
1.1       canacar   642:                if (state_buf == NULL || state_ord == NULL ||
                    643:                    state_cache == NULL)
                    644:                        err(1, "realloc");
                    645:                state_buf_len = len;
                    646:        }
                    647: }
                    648:
                    649: int
                    650: select_states(void)
                    651: {
                    652:        num_disp = num_states;
                    653:        return (0);
                    654: }
                    655:
                    656: int
                    657: read_states(void)
                    658: {
                    659:        struct pfioc_states ps;
1.43      bluhm     660:        size_t n;
1.1       canacar   661:
                    662:        if (pf_dev == -1)
                    663:                return -1;
                    664:
                    665:        for (;;) {
1.43      bluhm     666:                size_t sbytes = state_buf_len * sizeof(struct pfsync_state);
1.1       canacar   667:
                    668:                ps.ps_len = sbytes;
1.43      bluhm     669:                ps.ps_states = state_buf;
1.1       canacar   670:
1.44      deraadt   671:                if (ioctl(pf_dev, DIOCGETSTATES, &ps) == -1) {
1.1       canacar   672:                        error("DIOCGETSTATES");
                    673:                }
1.4       canacar   674:                num_states_all = ps.ps_len / sizeof(struct pfsync_state);
1.1       canacar   675:
                    676:                if (ps.ps_len < sbytes)
                    677:                        break;
                    678:
                    679:                alloc_buf(num_states_all);
                    680:        }
                    681:
1.43      bluhm     682:        num_states = num_states_all;
                    683:        for (n = 0; n < num_states_all; n++)
1.1       canacar   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:
                    696: int
1.42      kn        697: unmask(struct pf_addr * m)
1.1       canacar   698: {
1.42      kn        699:        int i = 31, j = 0, b = 0;
1.1       canacar   700:        u_int32_t tmp;
                    701:
1.42      kn        702:        while (j < 4 && m->addr32[j] == 0xffffffff) {
1.1       canacar   703:                b += 32;
                    704:                j++;
                    705:        }
1.42      kn        706:        if (j < 4) {
1.1       canacar   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:
                    716: void
                    717: tb_print_addr(struct pf_addr * addr, struct pf_addr * mask, int af)
                    718: {
1.47    ! jsg       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;
1.15      giovanni  726:        }
1.1       canacar   727:
                    728:        if (mask != NULL) {
                    729:                if (!PF_AZERO(mask, af))
1.42      kn        730:                        tbprintf("/%u", unmask(mask));
1.1       canacar   731:        }
                    732: }
1.4       canacar   733:
1.1       canacar   734: void
                    735: print_fld_host2(field_def *fld, struct pfsync_state_key *ks,
1.20      claudio   736:                struct pfsync_state_key *kn, int idx)
1.1       canacar   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:
1.20      claudio   744:        int asf = ks->af;
                    745:        int anf = kn->af;
                    746:
1.1       canacar   747:        if (fld == NULL)
                    748:                return;
                    749:
                    750:        if (fld->width < 3) {
                    751:                print_fld_str(fld, "*");
                    752:                return;
                    753:        }
                    754:
                    755:        tb_start();
1.20      claudio   756:        tb_print_addr(as, NULL, asf);
1.1       canacar   757:
1.20      claudio   758:        if (asf == AF_INET)
1.1       canacar   759:                tbprintf(":%u", ps);
                    760:        else
                    761:                tbprintf("[%u]", ps);
                    762:
                    763:        print_fld_tb(fld);
                    764:
1.20      claudio   765:        if (asf != anf || PF_ANEQ(as, an, asf) || ps != pn) {
1.1       canacar   766:                tb_start();
1.20      claudio   767:                tb_print_addr(an, NULL, anf);
1.1       canacar   768:
1.20      claudio   769:                if (anf == AF_INET)
1.1       canacar   770:                        tbprintf(":%u", pn);
                    771:                else
                    772:                        tbprintf("[%u]", pn);
                    773:                print_fld_tb(FLD_GW);
                    774:        }
                    775:
                    776: }
                    777:
                    778: void
                    779: print_fld_state(field_def *fld, unsigned int proto,
                    780:                unsigned int s1, unsigned int s2)
                    781: {
                    782:        int len;
1.26      sthen     783:
1.1       canacar   784:        if (fld == NULL)
                    785:                return;
                    786:
                    787:        len = fld->width;
                    788:        if (len < 1)
                    789:                return;
1.26      sthen     790:
1.1       canacar   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:
                    827: int
1.4       canacar   828: print_state(struct pfsync_state * s, struct sc_ent * ent)
1.1       canacar   829: {
1.4       canacar   830:        struct pfsync_state_peer *src, *dst;
1.1       canacar   831:        struct protoent *p;
1.4       canacar   832:        u_int64_t sz;
1.20      claudio   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;
1.1       canacar   837:
1.20      claudio   838:        if (dir == PF_OUT) {
1.1       canacar   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:
1.20      claudio   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);
1.1       canacar   860:        } else {
                    861:                print_fld_host2(FLD_SRC, &s->key[PF_SK_STACK],
1.20      claudio   862:                    &s->key[PF_SK_WIRE], 0);
1.1       canacar   863:                print_fld_host2(FLD_DEST, &s->key[PF_SK_STACK],
1.20      claudio   864:                    &s->key[PF_SK_WIRE], 1);
1.1       canacar   865:        }
                    866:
1.20      claudio   867:        if (dir == PF_OUT)
1.1       canacar   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);
1.3       mcbride   873:        print_fld_age(FLD_AGE, ntohl(s->creation));
                    874:        print_fld_age(FLD_EXP, ntohl(s->expire));
1.4       canacar   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);
1.3       mcbride   881:        print_fld_rate(FLD_SA, (s->creation) ?
1.33      canacar   882:                       ((double)sz/(double)ntohl(s->creation)) : -1);
1.1       canacar   883:
1.9       canacar   884:        print_fld_uint(FLD_RULE, ntohl(s->rule));
1.1       canacar   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:
                    894: void
                    895: print_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:
                    909: struct pf_rule *rules = NULL;
                    910: u_int32_t alloc_rules = 0;
                    911:
                    912: int
                    913: select_rules(void)
                    914: {
                    915:        num_disp = num_rules;
                    916:        return (0);
                    917: }
                    918:
                    919:
                    920: void
                    921: add_rule_alloc(u_int32_t nr)
                    922: {
                    923:        if (nr == 0)
                    924:                return;
                    925:
                    926:        num_rules += nr;
                    927:
                    928:        if (rules == NULL) {
1.29      doug      929:                rules = reallocarray(NULL, num_rules, sizeof(struct pf_rule));
1.1       canacar   930:                if (rules == NULL)
                    931:                        err(1, "malloc");
                    932:                alloc_rules = num_rules;
                    933:        } else if (num_rules > alloc_rules) {
1.29      doug      934:                rules = reallocarray(rules, num_rules, sizeof(struct pf_rule));
1.1       canacar   935:                if (rules == NULL)
                    936:                        err(1, "realloc");
                    937:                alloc_rules = num_rules;
                    938:        }
                    939: }
                    940:
                    941: int label_length;
                    942:
1.46      sashan    943: void
                    944: close_pf_trans(u_int32_t ticket)
                    945: {
                    946:        if (ioctl(pf_dev, DIOCXEND, &ticket) == -1)
                    947:                error("DIOCXEND: %s", strerror(errno));
                    948: }
                    949:
1.1       canacar   950: int
                    951: read_anchor_rules(char *anchor)
                    952: {
                    953:        struct pfioc_rule pr;
                    954:        u_int32_t nr, num, off;
1.4       canacar   955:        int len;
1.1       canacar   956:
                    957:        if (pf_dev < 0)
                    958:                return (-1);
                    959:
                    960:        memset(&pr, 0, sizeof(pr));
                    961:        strlcpy(pr.anchor, anchor, sizeof(pr.anchor));
1.4       canacar   962:
1.44      deraadt   963:        if (ioctl(pf_dev, DIOCGETRULES, &pr) == -1) {
1.1       canacar   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;
1.44      deraadt   974:                if (ioctl(pf_dev, DIOCGETRULE, &pr) == -1) {
1.1       canacar   975:                        error("DIOCGETRULE: %s", strerror(errno));
1.46      sashan    976:                        close_pf_trans(pr.ticket);
1.1       canacar   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;
1.4       canacar   982:                len = strlen(pr.rule.label);
                    983:                if (len > label_length)
                    984:                        label_length = len;
1.1       canacar   985:                rules[off + nr] = pr.rule;
                    986:        }
1.46      sashan    987:
                    988:        close_pf_trans(pr.ticket);
1.1       canacar   989:
                    990:        return (num);
                    991: }
                    992:
                    993: struct anchor_name {
1.30      deraadt   994:        char name[PATH_MAX];
1.1       canacar   995:        struct anchor_name *next;
                    996:        u_int32_t ref;
                    997: };
                    998:
                    999: struct anchor_name *anchor_root = NULL;
                   1000: struct anchor_name *anchor_end = NULL;
                   1001: struct anchor_name *anchor_free = NULL;
                   1002:
                   1003: struct anchor_name*
                   1004: alloc_anchor_name(const char *path)
                   1005: {
                   1006:        struct anchor_name *a;
                   1007:
                   1008:        a = anchor_free;
                   1009:        if (a == NULL) {
1.32      deraadt  1010:                a = malloc(sizeof(struct anchor_name));
1.1       canacar  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:
                   1027: void
                   1028: reset_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:
                   1038: struct pfioc_ruleset ruleset;
                   1039: char *rs_end = NULL;
                   1040:
                   1041: int
                   1042: read_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:
1.44      deraadt  1066:        if (ioctl(pf_dev, DIOCGETRULESETS, &ruleset) == -1) {
1.1       canacar  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;
1.44      deraadt  1085:                if (ioctl(pf_dev, DIOCGETRULESET, &ruleset) == -1) {
1.1       canacar  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:
                   1098: void
                   1099: compute_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:
                   1128: int
                   1129: read_rules(void)
                   1130: {
1.4       canacar  1131:        int ret, nw, mw;
1.1       canacar  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:
1.4       canacar  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;
1.1       canacar  1153:        }
                   1154:
                   1155:        num_disp = num_rules;
                   1156:        return (ret);
                   1157: }
                   1158:
                   1159: void
                   1160: tb_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:
                   1181: void
                   1182: tb_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:
                   1204: void
                   1205: tb_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:
                   1221: void
                   1222: tb_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");
1.26      sthen    1250:
1.1       canacar  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:
                   1270: void
1.45      millert  1271: tb_print_ugid(u_int8_t op, id_t i1, id_t i2, const char *t)
1.1       canacar  1272: {
                   1273:        char    a1[11], a2[11];
                   1274:
1.45      millert  1275:        snprintf(a1, sizeof(a1), "%u", i1);
                   1276:        snprintf(a2, sizeof(a2), "%u", i2);
1.1       canacar  1277:
                   1278:        tbprintf("%s ", t);
1.45      millert  1279:        if (i1 == -1 && (op == PF_OP_EQ || op == PF_OP_NE))
1.1       canacar  1280:                tb_print_op(op, "unknown", a2);
                   1281:        else
                   1282:                tb_print_op(op, a1, a2);
                   1283: }
                   1284:
                   1285: void
                   1286: tb_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:
                   1296: void
                   1297: print_rule(struct pf_rule *pr)
                   1298: {
1.11      henning  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" };
1.1       canacar  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]);
1.4       canacar  1316:
1.1       canacar  1317:        print_fld_uint(FLD_RULE, pr->nr);
1.5       sthen    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:
1.1       canacar  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");
1.31      jsg      1332:        else if (pr->keep_state == PF_STATE_SYNPROXY)
1.1       canacar  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:
1.12      canacar  1339:        if (pr->action >= numact)
1.1       canacar  1340:                print_fld_uint(FLD_ACTION, pr->action);
                   1341:        else print_fld_str(FLD_ACTION, actiontypes[pr->action]);
1.12      canacar  1342:
1.1       canacar  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);
1.4       canacar  1361:
1.1       canacar  1362:        /* print info field */
                   1363:
                   1364:        tb_start();
1.4       canacar  1365:
1.1       canacar  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:        }
1.4       canacar  1384:
1.1       canacar  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);
1.4       canacar  1393:
1.1       canacar  1394:        if (pr->uid.op)
                   1395:                tb_print_ugid(pr->uid.op, pr->uid.uid[0], pr->uid.uid[1],
1.45      millert  1396:                        "user");
1.1       canacar  1397:        if (pr->gid.op)
                   1398:                tb_print_ugid(pr->gid.op, pr->gid.gid[0], pr->gid.gid[1],
1.45      millert  1399:                        "group");
1.1       canacar  1400:
1.8       mcbride  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 ");
1.1       canacar  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:
1.10      henning  1436:        /* XXX more missing */
1.1       canacar  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);
1.4       canacar  1442:
1.1       canacar  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:        }
1.4       canacar  1450:
1.1       canacar  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:
                   1460: void
                   1461: print_rules(void)
                   1462: {
                   1463:        u_int32_t n, count = 0;
1.26      sthen    1464:
1.1       canacar  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 */
1.22      henning  1474: struct pfctl_queue_node *
                   1475: pfctl_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:
                   1486: void
                   1487: pfctl_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:
                   1508: int
                   1509: pfctl_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:
1.44      deraadt  1525:        if (ioctl(pf_dev, DIOCGETQUEUES, &pq) == -1) {
1.22      henning  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)
1.23      pelikan  1532:                while ((node = TAILQ_FIRST(&qnodes)) != NULL) {
1.22      henning  1533:                        TAILQ_REMOVE(&qnodes, node, entries);
1.23      pelikan  1534:                        free(node);
                   1535:                }
1.22      henning  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);
1.44      deraadt  1544:                if (ioctl(pf_dev, DIOCGETQSTATS, &pqs) == -1) {
1.22      henning  1545:                        error("DIOCGETQSTATS: %s", strerror(errno));
                   1546:                        return (-1);
                   1547:                }
1.36      mikeb    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:                }
1.22      henning  1559:        }
                   1560:        return (0);
                   1561: }
                   1562:
1.1       canacar  1563: int
                   1564: select_queues(void)
                   1565: {
1.24      henning  1566:        num_disp = num_queues;
1.1       canacar  1567:        return (0);
                   1568: }
                   1569:
                   1570: int
                   1571: read_queues(void)
                   1572: {
1.24      henning  1573:        num_disp = num_queues = 0;
1.22      henning  1574:
                   1575:        if (pfctl_update_qstats() < 0)
1.1       canacar  1576:                return (-1);
1.24      henning  1577:        num_disp = num_queues;
1.25      sthen    1578:
1.1       canacar  1579:        return(0);
                   1580: }
                   1581:
                   1582: double
                   1583: calc_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:
                   1593: double
                   1594: calc_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:
                   1602: double
                   1603: calc_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:
                   1611: void
1.22      henning  1612: print_queue_node(struct pfctl_queue_node *node)
                   1613: {
1.38      mikeb    1614:        u_int   rate, rtmp;
1.22      henning  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);
1.28      sthen    1623:        if (i == 0 && node->qs.ifname[0])
                   1624:                tbprintf(" on %s ", node->qs.ifname);
1.22      henning  1625:        print_fld_tb(FLD_QUEUE);
                   1626:
                   1627:        // XXX: missing min, max, burst
                   1628:        tb_start();
1.40      mikeb    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)) {
1.39      mikeb    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);
1.40      mikeb    1643:        } else
1.39      mikeb    1644:                tbprintf("%u%c", rate, unit[i]);
1.22      henning  1645:        print_fld_tb(FLD_BANDW);
1.39      mikeb    1646:
                   1647:        print_fld_str(FLD_SCHED, node->qs.flags & PFQS_FLOWQUEUE ?
                   1648:            "flow" : "fifo");
1.22      henning  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:
                   1679: void
1.1       canacar  1680: print_queues(void)
                   1681: {
1.22      henning  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;
1.1       canacar  1698:        }
                   1699: }
                   1700:
                   1701: /* main program functions */
                   1702:
                   1703: void
1.7       canacar  1704: update_cache(void)
1.1       canacar  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:
1.7       canacar  1723: int
1.1       canacar  1724: initpftop(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);
1.44      deraadt  1737:        } else if (ioctl(pf_dev, DIOCGETSTATUS, &status) == -1) {
1.1       canacar  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);
1.7       canacar  1753:
                   1754:        return (1);
1.1       canacar  1755: }