1 /* $OpenBSD: pftop.c,v 1.47 2024/04/22 14:19:48 jsg Exp $ */
2 /*
3 * Copyright (c) 2001, 2007 Can Erkin Acar
4 * Copyright (c) 2001 Daniel Hartmeier
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36
37 #include <net/if.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <netinet/tcp_fsm.h>
41 #include <net/pfvar.h>
42 #include <arpa/inet.h>
43
44 #include <net/hfsc.h>
45
46 #include <ctype.h>
47 #include <curses.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <netdb.h>
52 #include <signal.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <limits.h>
58 #include <stdarg.h>
59
60 #include "systat.h"
61 #include "engine.h"
62 #include "cache.h"
63
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
sort_size_callback(const void * s1,const void * s2)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
sort_pkt_callback(const void * s1,const void * s2)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
sort_age_callback(const void * s1,const void * s2)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
sort_exp_callback(const void * s1,const void * s2)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
sort_rate_callback(const void * s1,const void * s2)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
sort_peak_callback(const void * s1,const void * s2)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
compare_addr(int af,const struct pf_addr * a,const struct pf_addr * b)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
sort_addr_callback(const struct pfsync_state * s1,const struct pfsync_state * s2,int dir)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
sort_port_callback(const struct pfsync_state * s1,const struct pfsync_state * s2,int dir)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
sort_sa_callback(const void * p1,const void * p2)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
sort_da_callback(const void * p1,const void * p2)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
sort_sp_callback(const void * p1,const void * p2)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
sort_dp_callback(const void * p1,const void * p2)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
sort_states(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
alloc_buf(size_t ns)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
select_states(void)650 select_states(void)
651 {
652 num_disp = num_states;
653 return (0);
654 }
655
656 int
read_states(void)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
unmask(struct pf_addr * m)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
tb_print_addr(struct pf_addr * addr,struct pf_addr * mask,int af)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 case AF_INET6:
724 tbprintf("%s", inet6name(&addr->v6));
725 break;
726 }
727
728 if (mask != NULL) {
729 if (!PF_AZERO(mask, af))
730 tbprintf("/%u", unmask(mask));
731 }
732 }
733
734 void
print_fld_host2(field_def * fld,struct pfsync_state_key * ks,struct pfsync_state_key * kn,int idx)735 print_fld_host2(field_def *fld, struct pfsync_state_key *ks,
736 struct pfsync_state_key *kn, int idx)
737 {
738 struct pf_addr *as = &ks->addr[idx];
739 struct pf_addr *an = &kn->addr[idx];
740
741 u_int16_t ps = ntohs(ks->port[idx]);
742 u_int16_t pn = ntohs(kn->port[idx]);
743
744 int asf = ks->af;
745 int anf = kn->af;
746
747 if (fld == NULL)
748 return;
749
750 if (fld->width < 3) {
751 print_fld_str(fld, "*");
752 return;
753 }
754
755 tb_start();
756 tb_print_addr(as, NULL, asf);
757
758 if (asf == AF_INET)
759 tbprintf(":%u", ps);
760 else
761 tbprintf("[%u]", ps);
762
763 print_fld_tb(fld);
764
765 if (asf != anf || PF_ANEQ(as, an, asf) || ps != pn) {
766 tb_start();
767 tb_print_addr(an, NULL, anf);
768
769 if (anf == AF_INET)
770 tbprintf(":%u", pn);
771 else
772 tbprintf("[%u]", pn);
773 print_fld_tb(FLD_GW);
774 }
775
776 }
777
778 void
print_fld_state(field_def * fld,unsigned int proto,unsigned int s1,unsigned int s2)779 print_fld_state(field_def *fld, unsigned int proto,
780 unsigned int s1, unsigned int s2)
781 {
782 int len;
783
784 if (fld == NULL)
785 return;
786
787 len = fld->width;
788 if (len < 1)
789 return;
790
791 tb_start();
792
793 if (proto == IPPROTO_TCP) {
794 if (s1 <= TCPS_TIME_WAIT && s2 <= TCPS_TIME_WAIT)
795 tbprintf("%s:%s", tcpstates[s1], tcpstates[s2]);
796 #ifdef PF_TCPS_PROXY_SRC
797 else if (s1 == PF_TCPS_PROXY_SRC ||
798 s2 == PF_TCPS_PROXY_SRC)
799 tbprintf("PROXY:SRC\n");
800 else if (s1 == PF_TCPS_PROXY_DST ||
801 s2 == PF_TCPS_PROXY_DST)
802 tbprintf("PROXY:DST\n");
803 #endif
804 else
805 tbprintf("<BAD STATE LEVELS>");
806 } else if (proto == IPPROTO_UDP && s1 < PFUDPS_NSTATES &&
807 s2 < PFUDPS_NSTATES) {
808 const char *states[] = PFUDPS_NAMES;
809 tbprintf("%s:%s", states[s1], states[s2]);
810 } else if (proto != IPPROTO_ICMP && s1 < PFOTHERS_NSTATES &&
811 s2 < PFOTHERS_NSTATES) {
812 /* XXX ICMP doesn't really have state levels */
813 const char *states[] = PFOTHERS_NAMES;
814 tbprintf("%s:%s", states[s1], states[s2]);
815 } else {
816 tbprintf("%u:%u", s1, s2);
817 }
818
819 if (strlen(tmp_buf) > len) {
820 tb_start();
821 tbprintf("%u:%u", s1, s2);
822 }
823
824 print_fld_tb(fld);
825 }
826
827 int
print_state(struct pfsync_state * s,struct sc_ent * ent)828 print_state(struct pfsync_state * s, struct sc_ent * ent)
829 {
830 struct pfsync_state_peer *src, *dst;
831 struct protoent *p;
832 u_int64_t sz;
833 int afto, dir;
834
835 afto = s->key[PF_SK_STACK].af == s->key[PF_SK_WIRE].af ? 0 : 1;
836 dir = afto ? PF_OUT : s->direction;
837
838 if (dir == PF_OUT) {
839 src = &s->src;
840 dst = &s->dst;
841 } else {
842 src = &s->dst;
843 dst = &s->src;
844 }
845
846 p = getprotobynumber(s->proto);
847
848 if (p != NULL)
849 print_fld_str(FLD_PROTO, p->p_name);
850 else
851 print_fld_uint(FLD_PROTO, s->proto);
852
853 if (dir == PF_OUT) {
854 print_fld_host2(FLD_SRC,
855 &s->key[afto ? PF_SK_STACK : PF_SK_WIRE],
856 &s->key[PF_SK_STACK], 1);
857 print_fld_host2(FLD_DEST,
858 &s->key[afto ? PF_SK_STACK : PF_SK_WIRE],
859 &s->key[afto ? PF_SK_WIRE : PF_SK_STACK], 0);
860 } else {
861 print_fld_host2(FLD_SRC, &s->key[PF_SK_STACK],
862 &s->key[PF_SK_WIRE], 0);
863 print_fld_host2(FLD_DEST, &s->key[PF_SK_STACK],
864 &s->key[PF_SK_WIRE], 1);
865 }
866
867 if (dir == PF_OUT)
868 print_fld_str(FLD_DIR, "Out");
869 else
870 print_fld_str(FLD_DIR, "In");
871
872 print_fld_state(FLD_STATE, s->proto, src->state, dst->state);
873 print_fld_age(FLD_AGE, ntohl(s->creation));
874 print_fld_age(FLD_EXP, ntohl(s->expire));
875
876 sz = COUNTER(s->bytes[0]) + COUNTER(s->bytes[1]);
877
878 print_fld_size(FLD_PKTS, COUNTER(s->packets[0]) +
879 COUNTER(s->packets[1]));
880 print_fld_size(FLD_BYTES, sz);
881 print_fld_rate(FLD_SA, (s->creation) ?
882 ((double)sz/(double)ntohl(s->creation)) : -1);
883
884 print_fld_uint(FLD_RULE, ntohl(s->rule));
885 if (cachestates && ent != NULL) {
886 print_fld_rate(FLD_SI, ent->rate);
887 print_fld_rate(FLD_SP, ent->peak);
888 }
889
890 end_line();
891 return 1;
892 }
893
894 void
print_states(void)895 print_states(void)
896 {
897 int n, count = 0;
898
899 for (n = dispstart; n < num_disp; n++) {
900 count += print_state(state_buf + state_ord[n],
901 state_cache[state_ord[n]]);
902 if (maxprint > 0 && count >= maxprint)
903 break;
904 }
905 }
906
907 /* rule display */
908
909 struct pf_rule *rules = NULL;
910 u_int32_t alloc_rules = 0;
911
912 int
select_rules(void)913 select_rules(void)
914 {
915 num_disp = num_rules;
916 return (0);
917 }
918
919
920 void
add_rule_alloc(u_int32_t nr)921 add_rule_alloc(u_int32_t nr)
922 {
923 if (nr == 0)
924 return;
925
926 num_rules += nr;
927
928 if (rules == NULL) {
929 rules = reallocarray(NULL, num_rules, sizeof(struct pf_rule));
930 if (rules == NULL)
931 err(1, "malloc");
932 alloc_rules = num_rules;
933 } else if (num_rules > alloc_rules) {
934 rules = reallocarray(rules, num_rules, sizeof(struct pf_rule));
935 if (rules == NULL)
936 err(1, "realloc");
937 alloc_rules = num_rules;
938 }
939 }
940
941 int label_length;
942
943 void
close_pf_trans(u_int32_t ticket)944 close_pf_trans(u_int32_t ticket)
945 {
946 if (ioctl(pf_dev, DIOCXEND, &ticket) == -1)
947 error("DIOCXEND: %s", strerror(errno));
948 }
949
950 int
read_anchor_rules(char * anchor)951 read_anchor_rules(char *anchor)
952 {
953 struct pfioc_rule pr;
954 u_int32_t nr, num, off;
955 int len;
956
957 if (pf_dev < 0)
958 return (-1);
959
960 memset(&pr, 0, sizeof(pr));
961 strlcpy(pr.anchor, anchor, sizeof(pr.anchor));
962
963 if (ioctl(pf_dev, DIOCGETRULES, &pr) == -1) {
964 error("anchor %s: %s", anchor, strerror(errno));
965 return (-1);
966 }
967
968 off = num_rules;
969 num = pr.nr;
970 add_rule_alloc(num);
971
972 for (nr = 0; nr < num; ++nr) {
973 pr.nr = nr;
974 if (ioctl(pf_dev, DIOCGETRULE, &pr) == -1) {
975 error("DIOCGETRULE: %s", strerror(errno));
976 close_pf_trans(pr.ticket);
977 return (-1);
978 }
979 /* XXX overload pr.anchor, to store a pointer to
980 * anchor name */
981 pr.rule.anchor = (struct pf_anchor *) anchor;
982 len = strlen(pr.rule.label);
983 if (len > label_length)
984 label_length = len;
985 rules[off + nr] = pr.rule;
986 }
987
988 close_pf_trans(pr.ticket);
989
990 return (num);
991 }
992
993 struct anchor_name {
994 char name[PATH_MAX];
995 struct anchor_name *next;
996 u_int32_t ref;
997 };
998
999 struct anchor_name *anchor_root = NULL;
1000 struct anchor_name *anchor_end = NULL;
1001 struct anchor_name *anchor_free = NULL;
1002
1003 struct anchor_name*
alloc_anchor_name(const char * path)1004 alloc_anchor_name(const char *path)
1005 {
1006 struct anchor_name *a;
1007
1008 a = anchor_free;
1009 if (a == NULL) {
1010 a = malloc(sizeof(struct anchor_name));
1011 if (a == NULL)
1012 return (NULL);
1013 } else
1014 anchor_free = a->next;
1015
1016 if (anchor_root == NULL)
1017 anchor_end = a;
1018
1019 a->next = anchor_root;
1020 anchor_root = a;
1021
1022 a->ref = 0;
1023 strlcpy(a->name, path, sizeof(a->name));
1024 return (a);
1025 }
1026
1027 void
reset_anchor_names(void)1028 reset_anchor_names(void)
1029 {
1030 if (anchor_end == NULL)
1031 return;
1032
1033 anchor_end->next = anchor_free;
1034 anchor_free = anchor_root;
1035 anchor_root = anchor_end = NULL;
1036 }
1037
1038 struct pfioc_ruleset ruleset;
1039 char *rs_end = NULL;
1040
1041 int
read_rulesets(const char * path)1042 read_rulesets(const char *path)
1043 {
1044 char *pre;
1045 struct anchor_name *a;
1046 u_int32_t nr, ns;
1047 int len;
1048
1049 if (path == NULL)
1050 ruleset.path[0] = '\0';
1051 else if (strlcpy(ruleset.path, path, sizeof(ruleset.path)) >=
1052 sizeof(ruleset.path))
1053 return (-1);
1054
1055 /* a persistent storage for anchor names */
1056 a = alloc_anchor_name(ruleset.path);
1057 if (a == NULL)
1058 return (-1);
1059
1060 len = read_anchor_rules(a->name);
1061 if (len < 0)
1062 return (-1);
1063
1064 a->ref += len;
1065
1066 if (ioctl(pf_dev, DIOCGETRULESETS, &ruleset) == -1) {
1067 error("DIOCGETRULESETS: %s", strerror(errno));
1068 return (-1);
1069 }
1070
1071 ns = ruleset.nr;
1072
1073 if (rs_end == NULL)
1074 rs_end = ruleset.path + sizeof(ruleset.path);
1075
1076 /* 'pre' tracks the previous level on the anchor */
1077 pre = strchr(ruleset.path, 0);
1078 len = rs_end - pre;
1079 if (len < 1)
1080 return (-1);
1081 --len;
1082
1083 for (nr = 0; nr < ns; ++nr) {
1084 ruleset.nr = nr;
1085 if (ioctl(pf_dev, DIOCGETRULESET, &ruleset) == -1) {
1086 error("DIOCGETRULESET: %s", strerror(errno));
1087 return (-1);
1088 }
1089 *pre = '/';
1090 if (strlcpy(pre + 1, ruleset.name, len) < len)
1091 read_rulesets(ruleset.path);
1092 *pre = '\0';
1093 }
1094
1095 return (0);
1096 }
1097
1098 void
compute_anchor_field(void)1099 compute_anchor_field(void)
1100 {
1101 struct anchor_name *a;
1102 int sum, cnt, mx, nx;
1103 sum = cnt = mx = 0;
1104
1105 for (a = anchor_root; a != NULL; a = a->next, cnt++) {
1106 int len;
1107 if (a->ref == 0)
1108 continue;
1109 len = strlen(a->name);
1110 sum += len;
1111 if (len > mx)
1112 mx = len;
1113 }
1114
1115 nx = sum/cnt;
1116 if (nx < ANCHOR_FLD_SIZE)
1117 nx = (mx < ANCHOR_FLD_SIZE) ? mx : ANCHOR_FLD_SIZE;
1118
1119 if (FLD_ANCHOR->max_width != mx ||
1120 FLD_ANCHOR->norm_width != nx) {
1121 FLD_ANCHOR->max_width = mx;
1122 FLD_ANCHOR->norm_width = nx;
1123 field_setup();
1124 need_update = 1;
1125 }
1126 }
1127
1128 int
read_rules(void)1129 read_rules(void)
1130 {
1131 int ret, nw, mw;
1132 num_rules = 0;
1133
1134 if (pf_dev == -1)
1135 return (-1);
1136
1137 label_length = MIN_LABEL_SIZE;
1138
1139 reset_anchor_names();
1140 ret = read_rulesets(NULL);
1141 compute_anchor_field();
1142
1143 nw = mw = label_length;
1144 if (nw > 16)
1145 nw = 16;
1146
1147 if (FLD_LABEL->norm_width != nw ||
1148 FLD_LABEL->max_width != mw) {
1149 FLD_LABEL->norm_width = nw;
1150 FLD_LABEL->max_width = mw;
1151 field_setup();
1152 need_update = 1;
1153 }
1154
1155 num_disp = num_rules;
1156 return (ret);
1157 }
1158
1159 void
tb_print_addrw(struct pf_addr_wrap * addr,struct pf_addr * mask,u_int8_t af)1160 tb_print_addrw(struct pf_addr_wrap *addr, struct pf_addr *mask, u_int8_t af)
1161 {
1162 switch (addr->type) {
1163 case PF_ADDR_ADDRMASK:
1164 tb_print_addr(&addr->v.a.addr, mask, af);
1165 break;
1166 case PF_ADDR_NOROUTE:
1167 tbprintf("noroute");
1168 break;
1169 case PF_ADDR_DYNIFTL:
1170 tbprintf("(%s)", addr->v.ifname);
1171 break;
1172 case PF_ADDR_TABLE:
1173 tbprintf("<%s>", addr->v.tblname);
1174 break;
1175 default:
1176 tbprintf("UNKNOWN");
1177 break;
1178 }
1179 }
1180
1181 void
tb_print_op(u_int8_t op,const char * a1,const char * a2)1182 tb_print_op(u_int8_t op, const char *a1, const char *a2)
1183 {
1184 if (op == PF_OP_IRG)
1185 tbprintf("%s >< %s ", a1, a2);
1186 else if (op == PF_OP_XRG)
1187 tbprintf("%s <> %s ", a1, a2);
1188 else if (op == PF_OP_RRG)
1189 tbprintf("%s:%s ", a1, a2);
1190 else if (op == PF_OP_EQ)
1191 tbprintf("= %s ", a1);
1192 else if (op == PF_OP_NE)
1193 tbprintf("!= %s ", a1);
1194 else if (op == PF_OP_LT)
1195 tbprintf("< %s ", a1);
1196 else if (op == PF_OP_LE)
1197 tbprintf("<= %s ", a1);
1198 else if (op == PF_OP_GT)
1199 tbprintf("> %s ", a1);
1200 else if (op == PF_OP_GE)
1201 tbprintf(">= %s ", a1);
1202 }
1203
1204 void
tb_print_port(u_int8_t op,u_int16_t p1,u_int16_t p2,char * proto)1205 tb_print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
1206 {
1207 char a1[6], a2[6];
1208 struct servent *s = getservbyport(p1, proto);
1209
1210 p1 = ntohs(p1);
1211 p2 = ntohs(p2);
1212 snprintf(a1, sizeof(a1), "%u", p1);
1213 snprintf(a2, sizeof(a2), "%u", p2);
1214 tbprintf("port ");
1215 if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
1216 tb_print_op(op, s->s_name, a2);
1217 else
1218 tb_print_op(op, a1, a2);
1219 }
1220
1221 void
tb_print_fromto(struct pf_rule_addr * src,struct pf_rule_addr * dst,u_int8_t af,u_int8_t proto)1222 tb_print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst,
1223 u_int8_t af, u_int8_t proto)
1224 {
1225 if (
1226 PF_AZERO(PT_ADDR(src), AF_INET6) &&
1227 PF_AZERO(PT_ADDR(dst), AF_INET6) &&
1228 ! PT_NOROUTE(src) && ! PT_NOROUTE(dst) &&
1229 PF_AZERO(PT_MASK(src), AF_INET6) &&
1230 PF_AZERO(PT_MASK(dst), AF_INET6) &&
1231 !src->port_op && !dst->port_op)
1232 tbprintf("all ");
1233 else {
1234 tbprintf("from ");
1235 if (PT_NOROUTE(src))
1236 tbprintf("no-route ");
1237 else if (PF_AZERO(PT_ADDR(src), AF_INET6) &&
1238 PF_AZERO(PT_MASK(src), AF_INET6))
1239 tbprintf("any ");
1240 else {
1241 if (src->neg)
1242 tbprintf("! ");
1243 tb_print_addrw(&src->addr, PT_MASK(src), af);
1244 tbprintf(" ");
1245 }
1246 if (src->port_op)
1247 tb_print_port(src->port_op, src->port[0],
1248 src->port[1],
1249 proto == IPPROTO_TCP ? "tcp" : "udp");
1250
1251 tbprintf("to ");
1252 if (PT_NOROUTE(dst))
1253 tbprintf("no-route ");
1254 else if (PF_AZERO(PT_ADDR(dst), AF_INET6) &&
1255 PF_AZERO(PT_MASK(dst), AF_INET6))
1256 tbprintf("any ");
1257 else {
1258 if (dst->neg)
1259 tbprintf("! ");
1260 tb_print_addrw(&dst->addr, PT_MASK(dst), af);
1261 tbprintf(" ");
1262 }
1263 if (dst->port_op)
1264 tb_print_port(dst->port_op, dst->port[0],
1265 dst->port[1],
1266 proto == IPPROTO_TCP ? "tcp" : "udp");
1267 }
1268 }
1269
1270 void
tb_print_ugid(u_int8_t op,id_t i1,id_t i2,const char * t)1271 tb_print_ugid(u_int8_t op, id_t i1, id_t i2, const char *t)
1272 {
1273 char a1[11], a2[11];
1274
1275 snprintf(a1, sizeof(a1), "%u", i1);
1276 snprintf(a2, sizeof(a2), "%u", i2);
1277
1278 tbprintf("%s ", t);
1279 if (i1 == -1 && (op == PF_OP_EQ || op == PF_OP_NE))
1280 tb_print_op(op, "unknown", a2);
1281 else
1282 tb_print_op(op, a1, a2);
1283 }
1284
1285 void
tb_print_flags(u_int8_t f)1286 tb_print_flags(u_int8_t f)
1287 {
1288 const char *tcpflags = "FSRPAUEW";
1289 int i;
1290
1291 for (i = 0; tcpflags[i]; ++i)
1292 if (f & (1 << i))
1293 tbprintf("%c", tcpflags[i]);
1294 }
1295
1296 void
print_rule(struct pf_rule * pr)1297 print_rule(struct pf_rule *pr)
1298 {
1299 static const char *actiontypes[] = { "Pass", "Block", "Scrub",
1300 "no Scrub", "Nat", "no Nat", "Binat", "no Binat", "Rdr",
1301 "no Rdr", "SynProxy Block", "Defer", "Match" };
1302 int numact = sizeof(actiontypes) / sizeof(char *);
1303
1304 static const char *routetypes[] = { "", "fastroute", "route-to",
1305 "dup-to", "reply-to" };
1306
1307 int numroute = sizeof(routetypes) / sizeof(char *);
1308
1309 if (pr == NULL) return;
1310
1311 print_fld_str(FLD_LABEL, pr->label);
1312 print_fld_size(FLD_STATS, pr->states_tot);
1313
1314 print_fld_size(FLD_PKTS, pr->packets[0] + pr->packets[1]);
1315 print_fld_size(FLD_BYTES, pr->bytes[0] + pr->bytes[1]);
1316
1317 print_fld_uint(FLD_RULE, pr->nr);
1318 if (pr->direction == PF_OUT)
1319 print_fld_str(FLD_DIR, "Out");
1320 else if (pr->direction == PF_IN)
1321 print_fld_str(FLD_DIR, "In");
1322 else
1323 print_fld_str(FLD_DIR, "Any");
1324
1325 if (pr->quick)
1326 print_fld_str(FLD_QUICK, "Quick");
1327
1328 if (pr->keep_state == PF_STATE_NORMAL)
1329 print_fld_str(FLD_KST, "Keep");
1330 else if (pr->keep_state == PF_STATE_MODULATE)
1331 print_fld_str(FLD_KST, "Mod");
1332 else if (pr->keep_state == PF_STATE_SYNPROXY)
1333 print_fld_str(FLD_KST, "Syn");
1334 if (pr->log == 1)
1335 print_fld_str(FLD_LOG, "Log");
1336 else if (pr->log == 2)
1337 print_fld_str(FLD_LOG, "All");
1338
1339 if (pr->action >= numact)
1340 print_fld_uint(FLD_ACTION, pr->action);
1341 else print_fld_str(FLD_ACTION, actiontypes[pr->action]);
1342
1343 if (pr->proto) {
1344 struct protoent *p = getprotobynumber(pr->proto);
1345
1346 if (p != NULL)
1347 print_fld_str(FLD_PROTO, p->p_name);
1348 else
1349 print_fld_uint(FLD_PROTO, pr->proto);
1350 }
1351
1352 if (pr->ifname[0]) {
1353 tb_start();
1354 if (pr->ifnot)
1355 tbprintf("!");
1356 tbprintf("%s", pr->ifname);
1357 print_fld_tb(FLD_IF);
1358 }
1359 if (pr->max_states)
1360 print_fld_uint(FLD_STMAX, pr->max_states);
1361
1362 /* print info field */
1363
1364 tb_start();
1365
1366 if (pr->action == PF_DROP) {
1367 if (pr->rule_flag & PFRULE_RETURNRST)
1368 tbprintf("return-rst ");
1369 #ifdef PFRULE_RETURN
1370 else if (pr->rule_flag & PFRULE_RETURN)
1371 tbprintf("return ");
1372 #endif
1373 #ifdef PFRULE_RETURNICMP
1374 else if (pr->rule_flag & PFRULE_RETURNICMP)
1375 tbprintf("return-icmp ");
1376 #endif
1377 else
1378 tbprintf("drop ");
1379 }
1380
1381 if (pr->rt > 0 && pr->rt < numroute) {
1382 tbprintf("%s ", routetypes[pr->rt]);
1383 }
1384
1385 if (pr->af) {
1386 if (pr->af == AF_INET)
1387 tbprintf("inet ");
1388 else
1389 tbprintf("inet6 ");
1390 }
1391
1392 tb_print_fromto(&pr->src, &pr->dst, pr->af, pr->proto);
1393
1394 if (pr->uid.op)
1395 tb_print_ugid(pr->uid.op, pr->uid.uid[0], pr->uid.uid[1],
1396 "user");
1397 if (pr->gid.op)
1398 tb_print_ugid(pr->gid.op, pr->gid.gid[0], pr->gid.gid[1],
1399 "group");
1400
1401 if (pr->action == PF_PASS &&
1402 (pr->proto == 0 || pr->proto == IPPROTO_TCP) &&
1403 (pr->flags != TH_SYN || pr->flagset != (TH_SYN | TH_ACK) )) {
1404 tbprintf("flags ");
1405 if (pr->flags || pr->flagset) {
1406 tb_print_flags(pr->flags);
1407 tbprintf("/");
1408 tb_print_flags(pr->flagset);
1409 } else
1410 tbprintf("any ");
1411 }
1412
1413 tbprintf(" ");
1414
1415 if (pr->tos)
1416 tbprintf("tos 0x%2.2x ", pr->tos);
1417 #ifdef PFRULE_FRAGMENT
1418 if (pr->rule_flag & PFRULE_FRAGMENT)
1419 tbprintf("fragment ");
1420 #endif
1421 #ifdef PFRULE_NODF
1422 if (pr->rule_flag & PFRULE_NODF)
1423 tbprintf("no-df ");
1424 #endif
1425 #ifdef PFRULE_RANDOMID
1426 if (pr->rule_flag & PFRULE_RANDOMID)
1427 tbprintf("random-id ");
1428 #endif
1429 if (pr->min_ttl)
1430 tbprintf("min-ttl %d ", pr->min_ttl);
1431 if (pr->max_mss)
1432 tbprintf("max-mss %d ", pr->max_mss);
1433 if (pr->allow_opts)
1434 tbprintf("allow-opts ");
1435
1436 /* XXX more missing */
1437
1438 if (pr->qname[0] && pr->pqname[0])
1439 tbprintf("queue(%s, %s) ", pr->qname, pr->pqname);
1440 else if (pr->qname[0])
1441 tbprintf("queue %s ", pr->qname);
1442
1443 if (pr->tagname[0])
1444 tbprintf("tag %s ", pr->tagname);
1445 if (pr->match_tagname[0]) {
1446 if (pr->match_tag_not)
1447 tbprintf("! ");
1448 tbprintf("tagged %s ", pr->match_tagname);
1449 }
1450
1451 print_fld_tb(FLD_RINFO);
1452
1453 /* XXX anchor field overloaded with anchor name */
1454 print_fld_str(FLD_ANCHOR, (char *)pr->anchor);
1455 tb_end();
1456
1457 end_line();
1458 }
1459
1460 void
print_rules(void)1461 print_rules(void)
1462 {
1463 u_int32_t n, count = 0;
1464
1465 for (n = dispstart; n < num_rules; n++) {
1466 print_rule(rules + n);
1467 count ++;
1468 if (maxprint > 0 && count >= maxprint)
1469 break;
1470 }
1471 }
1472
1473 /* queue display */
1474 struct pfctl_queue_node *
pfctl_find_queue_node(const char * qname,const char * ifname)1475 pfctl_find_queue_node(const char *qname, const char *ifname)
1476 {
1477 struct pfctl_queue_node *node;
1478
1479 TAILQ_FOREACH(node, &qnodes, entries)
1480 if (!strcmp(node->qs.qname, qname)
1481 && !(strcmp(node->qs.ifname, ifname)))
1482 return (node);
1483 return (NULL);
1484 }
1485
1486 void
pfctl_insert_queue_node(const struct pf_queuespec qs,const struct queue_stats qstats)1487 pfctl_insert_queue_node(const struct pf_queuespec qs,
1488 const struct queue_stats qstats)
1489 {
1490 struct pfctl_queue_node *node, *parent;
1491
1492 node = calloc(1, sizeof(struct pfctl_queue_node));
1493 if (node == NULL)
1494 err(1, "pfctl_insert_queue_node: calloc");
1495 memcpy(&node->qs, &qs, sizeof(qs));
1496 memcpy(&node->qstats, &qstats, sizeof(qstats));
1497
1498 if (node->qs.parent[0]) {
1499 parent = pfctl_find_queue_node(node->qs.parent,
1500 node->qs.ifname);
1501 if (parent)
1502 node->depth = parent->depth + 1;
1503 }
1504
1505 TAILQ_INSERT_TAIL(&qnodes, node, entries);
1506 }
1507
1508 int
pfctl_update_qstats(void)1509 pfctl_update_qstats(void)
1510 {
1511 struct pfctl_queue_node *node;
1512 struct pfioc_queue pq;
1513 struct pfioc_qstats pqs;
1514 u_int32_t mnr, nr;
1515 struct queue_stats qstats;
1516 static u_int32_t last_ticket;
1517
1518 memset(&pq, 0, sizeof(pq));
1519 memset(&pqs, 0, sizeof(pqs));
1520 memset(&qstats, 0, sizeof(qstats));
1521
1522 if (pf_dev < 0)
1523 return (-1);
1524
1525 if (ioctl(pf_dev, DIOCGETQUEUES, &pq) == -1) {
1526 error("DIOCGETQUEUES: %s", strerror(errno));
1527 return (-1);
1528 }
1529
1530 /* if a new set is found, start over */
1531 if (pq.ticket != last_ticket)
1532 while ((node = TAILQ_FIRST(&qnodes)) != NULL) {
1533 TAILQ_REMOVE(&qnodes, node, entries);
1534 free(node);
1535 }
1536 last_ticket = pq.ticket;
1537
1538 num_queues = mnr = pq.nr;
1539 for (nr = 0; nr < mnr; ++nr) {
1540 pqs.nr = nr;
1541 pqs.ticket = pq.ticket;
1542 pqs.buf = &qstats.data;
1543 pqs.nbytes = sizeof(qstats.data);
1544 if (ioctl(pf_dev, DIOCGETQSTATS, &pqs) == -1) {
1545 error("DIOCGETQSTATS: %s", strerror(errno));
1546 return (-1);
1547 }
1548 qstats.valid = 1;
1549 gettimeofday(&qstats.timestamp, NULL);
1550 if ((node = pfctl_find_queue_node(pqs.queue.qname,
1551 pqs.queue.ifname)) != NULL) {
1552 memcpy(&node->qstats_last, &node->qstats,
1553 sizeof(struct queue_stats));
1554 memcpy(&node->qstats, &qstats,
1555 sizeof(struct queue_stats));
1556 } else {
1557 pfctl_insert_queue_node(pqs.queue, qstats);
1558 }
1559 }
1560 return (0);
1561 }
1562
1563 int
select_queues(void)1564 select_queues(void)
1565 {
1566 num_disp = num_queues;
1567 return (0);
1568 }
1569
1570 int
read_queues(void)1571 read_queues(void)
1572 {
1573 num_disp = num_queues = 0;
1574
1575 if (pfctl_update_qstats() < 0)
1576 return (-1);
1577 num_disp = num_queues;
1578
1579 return(0);
1580 }
1581
1582 double
calc_interval(struct timeval * cur_time,struct timeval * last_time)1583 calc_interval(struct timeval *cur_time, struct timeval *last_time)
1584 {
1585 double sec;
1586
1587 sec = (double)(cur_time->tv_sec - last_time->tv_sec) +
1588 (double)(cur_time->tv_usec - last_time->tv_usec) / 1000000;
1589
1590 return (sec);
1591 }
1592
1593 double
calc_rate(u_int64_t new_bytes,u_int64_t last_bytes,double interval)1594 calc_rate(u_int64_t new_bytes, u_int64_t last_bytes, double interval)
1595 {
1596 double rate;
1597
1598 rate = (double)(new_bytes - last_bytes) / interval;
1599 return (rate);
1600 }
1601
1602 double
calc_pps(u_int64_t new_pkts,u_int64_t last_pkts,double interval)1603 calc_pps(u_int64_t new_pkts, u_int64_t last_pkts, double interval)
1604 {
1605 double pps;
1606
1607 pps = (double)(new_pkts - last_pkts) / interval;
1608 return (pps);
1609 }
1610
1611 void
print_queue_node(struct pfctl_queue_node * node)1612 print_queue_node(struct pfctl_queue_node *node)
1613 {
1614 u_int rate, rtmp;
1615 int i;
1616 double interval, pps, bps;
1617 static const char unit[] = " KMG";
1618
1619 tb_start();
1620 for (i = 0; i < node->depth; i++)
1621 tbprintf(" ");
1622 tbprintf("%s", node->qs.qname);
1623 if (i == 0 && node->qs.ifname[0])
1624 tbprintf(" on %s ", node->qs.ifname);
1625 print_fld_tb(FLD_QUEUE);
1626
1627 // XXX: missing min, max, burst
1628 tb_start();
1629 rate = node->qs.linkshare.m2.absolute;
1630 for (i = 0; rate > 9999 && i <= 3; i++) {
1631 rtmp = rate / 1000;
1632 if (rtmp <= 9999)
1633 rtmp += (rate % 1000) / 500;
1634 rate = rtmp;
1635 }
1636 if (rate == 0 && (node->qs.flags & PFQS_FLOWQUEUE)) {
1637 /*
1638 * XXX We're abusing the fact that 'flows' in
1639 * the fqcodel_stats structure is at the same
1640 * spot as the 'period' in hfsc_class_stats.
1641 */
1642 tbprintf("%u", node->qstats.data.period);
1643 } else
1644 tbprintf("%u%c", rate, unit[i]);
1645 print_fld_tb(FLD_BANDW);
1646
1647 print_fld_str(FLD_SCHED, node->qs.flags & PFQS_FLOWQUEUE ?
1648 "flow" : "fifo");
1649
1650 if (node->qstats.valid && node->qstats_last.valid)
1651 interval = calc_interval(&node->qstats.timestamp,
1652 &node->qstats_last.timestamp);
1653 else
1654 interval = 0;
1655
1656 print_fld_size(FLD_PKTS, node->qstats.data.xmit_cnt.packets);
1657 print_fld_size(FLD_BYTES, node->qstats.data.xmit_cnt.bytes);
1658 print_fld_size(FLD_DROPP, node->qstats.data.drop_cnt.packets);
1659 print_fld_size(FLD_DROPB, node->qstats.data.drop_cnt.bytes);
1660 print_fld_size(FLD_QLEN, node->qstats.data.qlength);
1661
1662 if (interval > 0) {
1663 pps = calc_pps(node->qstats.data.xmit_cnt.packets,
1664 node->qstats_last.data.xmit_cnt.packets, interval);
1665 bps = calc_rate(node->qstats.data.xmit_cnt.bytes,
1666 node->qstats_last.data.xmit_cnt.bytes, interval);
1667
1668 tb_start();
1669 if (pps > 0 && pps < 1)
1670 tbprintf("%-3.1lf", pps);
1671 else
1672 tbprintf("%u", (unsigned int)pps);
1673
1674 print_fld_tb(FLD_PKTSPS);
1675 print_fld_bw(FLD_BYTESPS, bps);
1676 }
1677 }
1678
1679 void
print_queues(void)1680 print_queues(void)
1681 {
1682 uint32_t n, count, start;
1683 struct pfctl_queue_node *node;
1684
1685 n = count = 0;
1686 start = dispstart;
1687
1688 TAILQ_FOREACH(node, &qnodes, entries) {
1689 if (n < start) {
1690 n++;
1691 continue;
1692 }
1693 print_queue_node(node);
1694 end_line();
1695 count++;
1696 if (maxprint > 0 && count >= maxprint)
1697 return;
1698 }
1699 }
1700
1701 /* main program functions */
1702
1703 void
update_cache(void)1704 update_cache(void)
1705 {
1706 static int pstate = -1;
1707 if (pstate == cachestates)
1708 return;
1709
1710 pstate = cachestates;
1711 if (cachestates) {
1712 show_field(FLD_SI);
1713 show_field(FLD_SP);
1714 gotsig_alarm = 1;
1715 } else {
1716 hide_field(FLD_SI);
1717 hide_field(FLD_SP);
1718 need_update = 1;
1719 }
1720 field_setup();
1721 }
1722
1723 int
initpftop(void)1724 initpftop(void)
1725 {
1726 struct pf_status status;
1727 field_view *v;
1728 int cachesize = DEFAULT_CACHE_SIZE;
1729
1730 v = views;
1731 while(v->name != NULL)
1732 add_view(v++);
1733
1734 pf_dev = open("/dev/pf", O_RDONLY);
1735 if (pf_dev == -1) {
1736 alloc_buf(0);
1737 } else if (ioctl(pf_dev, DIOCGETSTATUS, &status) == -1) {
1738 warn("DIOCGETSTATUS");
1739 alloc_buf(0);
1740 } else
1741 alloc_buf(status.states);
1742
1743 /* initialize cache with given size */
1744 if (cache_init(cachesize))
1745 warnx("Failed to initialize cache.");
1746 else if (interactive && cachesize > 0)
1747 cachestates = 1;
1748
1749 update_cache();
1750
1751 show_field(FLD_STMAX);
1752 show_field(FLD_ANCHOR);
1753
1754 return (1);
1755 }
1756