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