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