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