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