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