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