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