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