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