Commit | Line | Data |
---|---|---|
70224baa | 1 | /* $OpenBSD: pf_print_state.c,v 1.44 2007/03/01 17:20:53 deraadt Exp $ */ |
95cc27f0 JS |
2 | |
3 | /* | |
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 | ||
a798b49f | 33 | #include <sys/types.h> |
95cc27f0 | 34 | #include <sys/socket.h> |
70224baa | 35 | #include <sys/endian.h> |
95cc27f0 JS |
36 | #include <net/if.h> |
37 | #define TCPSTATES | |
38 | #include <netinet/tcp_fsm.h> | |
39 | #include <net/pf/pfvar.h> | |
40 | #include <arpa/inet.h> | |
41 | #include <netdb.h> | |
42 | ||
43 | #include <stdio.h> | |
44 | #include <string.h> | |
45 | ||
46 | #include "pfctl_parser.h" | |
47 | #include "pfctl.h" | |
48 | ||
49 | void print_name(struct pf_addr *, sa_family_t); | |
50 | ||
51 | void | |
52 | print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) | |
53 | { | |
54 | switch (addr->type) { | |
55 | case PF_ADDR_DYNIFTL: | |
56 | printf("(%s", addr->v.ifname); | |
57 | if (addr->iflags & PFI_AFLAG_NETWORK) | |
58 | printf(":network"); | |
59 | if (addr->iflags & PFI_AFLAG_BROADCAST) | |
60 | printf(":broadcast"); | |
61 | if (addr->iflags & PFI_AFLAG_PEER) | |
62 | printf(":peer"); | |
63 | if (addr->iflags & PFI_AFLAG_NOALIAS) | |
64 | printf(":0"); | |
65 | if (verbose) { | |
66 | if (addr->p.dyncnt <= 0) | |
67 | printf(":*"); | |
68 | else | |
69 | printf(":%d", addr->p.dyncnt); | |
70 | } | |
71 | printf(")"); | |
72 | break; | |
73 | case PF_ADDR_TABLE: | |
74 | if (verbose) | |
75 | if (addr->p.tblcnt == -1) | |
76 | printf("<%s:*>", addr->v.tblname); | |
77 | else | |
78 | printf("<%s:%d>", addr->v.tblname, | |
79 | addr->p.tblcnt); | |
80 | else | |
81 | printf("<%s>", addr->v.tblname); | |
82 | return; | |
83 | case PF_ADDR_ADDRMASK: | |
84 | if (PF_AZERO(&addr->v.a.addr, AF_INET6) && | |
85 | PF_AZERO(&addr->v.a.mask, AF_INET6)) | |
86 | printf("any"); | |
87 | else { | |
88 | char buf[48]; | |
89 | ||
90 | if (inet_ntop(af, &addr->v.a.addr, buf, | |
91 | sizeof(buf)) == NULL) | |
92 | printf("?"); | |
93 | else | |
94 | printf("%s", buf); | |
95 | } | |
96 | break; | |
97 | case PF_ADDR_NOROUTE: | |
98 | printf("no-route"); | |
99 | return; | |
70224baa JL |
100 | case PF_ADDR_URPFFAILED: |
101 | printf("urpf-failed"); | |
102 | return; | |
103 | case PF_ADDR_RTLABEL: | |
104 | printf("route \"%s\"", addr->v.rtlabelname); | |
105 | return; | |
95cc27f0 JS |
106 | default: |
107 | printf("?"); | |
108 | return; | |
109 | } | |
110 | ||
111 | /* mask if not _both_ address and mask are zero */ | |
112 | if (!(PF_AZERO(&addr->v.a.addr, AF_INET6) && | |
113 | PF_AZERO(&addr->v.a.mask, AF_INET6))) { | |
114 | int bits = unmask(&addr->v.a.mask, af); | |
115 | ||
116 | if (bits != (af == AF_INET ? 32 : 128)) | |
117 | printf("/%d", bits); | |
118 | } | |
119 | } | |
120 | ||
121 | void | |
122 | print_name(struct pf_addr *addr, sa_family_t af) | |
123 | { | |
70224baa | 124 | char his_host[NI_MAXHOST]; |
95cc27f0 | 125 | |
70224baa | 126 | strlcpy(his_host, "?", sizeof(his_host)); |
95cc27f0 JS |
127 | switch (af) { |
128 | case AF_INET: { | |
70224baa | 129 | struct sockaddr_in sin; |
95cc27f0 | 130 | |
70224baa JL |
131 | memset(&sin, 0, sizeof(sin)); |
132 | sin.sin_len = sizeof(sin); | |
133 | sin.sin_family = AF_INET; | |
134 | sin.sin_addr = addr->v4; | |
135 | getnameinfo((struct sockaddr *)&sin, sin.sin_len, | |
136 | his_host, sizeof(his_host), NULL, 0, NI_NOFQDN); | |
95cc27f0 JS |
137 | break; |
138 | } | |
139 | case AF_INET6: { | |
140 | struct sockaddr_in6 sin6; | |
141 | ||
142 | memset(&sin6, 0, sizeof(sin6)); | |
143 | sin6.sin6_len = sizeof(sin6); | |
144 | sin6.sin6_family = AF_INET6; | |
145 | sin6.sin6_addr = addr->v6; | |
146 | getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, | |
70224baa | 147 | his_host, sizeof(his_host), NULL, 0, NI_NOFQDN); |
95cc27f0 JS |
148 | break; |
149 | } | |
150 | } | |
70224baa | 151 | printf("%s", his_host); |
95cc27f0 JS |
152 | } |
153 | ||
154 | void | |
155 | print_host(struct pf_state_host *h, sa_family_t af, int opts) | |
156 | { | |
157 | u_int16_t p = ntohs(h->port); | |
158 | ||
159 | if (opts & PF_OPT_USEDNS) | |
160 | print_name(&h->addr, af); | |
161 | else { | |
162 | struct pf_addr_wrap aw; | |
163 | ||
164 | memset(&aw, 0, sizeof(aw)); | |
165 | aw.v.a.addr = h->addr; | |
166 | if (af == AF_INET) | |
167 | aw.v.a.mask.addr32[0] = 0xffffffff; | |
168 | else { | |
169 | memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); | |
170 | af = AF_INET6; | |
171 | } | |
172 | print_addr(&aw, af, opts & PF_OPT_VERBOSE2); | |
173 | } | |
174 | ||
175 | if (p) { | |
176 | if (af == AF_INET) | |
177 | printf(":%u", p); | |
178 | else | |
179 | printf("[%u]", p); | |
180 | } | |
181 | } | |
182 | ||
183 | void | |
184 | print_seq(struct pf_state_peer *p) | |
185 | { | |
186 | if (p->seqdiff) | |
187 | printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo, | |
188 | p->seqdiff); | |
189 | else | |
190 | printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo); | |
191 | } | |
192 | ||
193 | void | |
194 | print_state(struct pf_state *s, int opts) | |
195 | { | |
196 | struct pf_state_peer *src, *dst; | |
197 | struct protoent *p; | |
198 | int min, sec; | |
199 | ||
200 | if (s->direction == PF_OUT) { | |
201 | src = &s->src; | |
202 | dst = &s->dst; | |
203 | } else { | |
204 | src = &s->dst; | |
205 | dst = &s->src; | |
206 | } | |
207 | printf("%s ", s->u.ifname); | |
208 | if ((p = getprotobynumber(s->proto)) != NULL) | |
209 | printf("%s ", p->p_name); | |
210 | else | |
211 | printf("%u ", s->proto); | |
212 | if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) || | |
213 | (s->lan.port != s->gwy.port)) { | |
214 | print_host(&s->lan, s->af, opts); | |
215 | if (s->direction == PF_OUT) | |
216 | printf(" -> "); | |
217 | else | |
218 | printf(" <- "); | |
219 | } | |
220 | print_host(&s->gwy, s->af, opts); | |
221 | if (s->direction == PF_OUT) | |
222 | printf(" -> "); | |
223 | else | |
224 | printf(" <- "); | |
225 | print_host(&s->ext, s->af, opts); | |
226 | ||
227 | printf(" "); | |
228 | if (s->proto == IPPROTO_TCP) { | |
229 | if (src->state <= TCPS_TIME_WAIT && | |
230 | dst->state <= TCPS_TIME_WAIT) | |
231 | printf(" %s:%s\n", tcpstates[src->state], | |
232 | tcpstates[dst->state]); | |
233 | else if (src->state == PF_TCPS_PROXY_SRC || | |
234 | dst->state == PF_TCPS_PROXY_SRC) | |
235 | printf(" PROXY:SRC\n"); | |
236 | else if (src->state == PF_TCPS_PROXY_DST || | |
237 | dst->state == PF_TCPS_PROXY_DST) | |
238 | printf(" PROXY:DST\n"); | |
239 | else | |
240 | printf(" <BAD STATE LEVELS %u:%u>\n", | |
241 | src->state, dst->state); | |
242 | if (opts & PF_OPT_VERBOSE) { | |
243 | printf(" "); | |
244 | print_seq(src); | |
245 | if (src->wscale && dst->wscale) | |
246 | printf(" wscale %u", | |
247 | src->wscale & PF_WSCALE_MASK); | |
248 | printf(" "); | |
249 | print_seq(dst); | |
250 | if (src->wscale && dst->wscale) | |
251 | printf(" wscale %u", | |
252 | dst->wscale & PF_WSCALE_MASK); | |
253 | printf("\n"); | |
254 | } | |
255 | } else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES && | |
256 | dst->state < PFUDPS_NSTATES) { | |
257 | const char *states[] = PFUDPS_NAMES; | |
258 | ||
259 | printf(" %s:%s\n", states[src->state], states[dst->state]); | |
260 | } else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES && | |
261 | dst->state < PFOTHERS_NSTATES) { | |
262 | /* XXX ICMP doesn't really have state levels */ | |
263 | const char *states[] = PFOTHERS_NAMES; | |
264 | ||
265 | printf(" %s:%s\n", states[src->state], states[dst->state]); | |
266 | } else { | |
267 | printf(" %u:%u\n", src->state, dst->state); | |
268 | } | |
269 | ||
270 | if (opts & PF_OPT_VERBOSE) { | |
271 | sec = s->creation % 60; | |
272 | s->creation /= 60; | |
273 | min = s->creation % 60; | |
274 | s->creation /= 60; | |
275 | printf(" age %.2u:%.2u:%.2u", s->creation, min, sec); | |
276 | sec = s->expire % 60; | |
277 | s->expire /= 60; | |
278 | min = s->expire % 60; | |
279 | s->expire /= 60; | |
280 | printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec); | |
3b6d4e6a SW |
281 | printf(", %ju:%ju pkts, %ju:%ju bytes", |
282 | (uintmax_t)s->packets[0], (uintmax_t)s->packets[1], | |
283 | (uintmax_t)s->bytes[0], (uintmax_t)s->bytes[1]); | |
70224baa | 284 | if (s->anchor.nr != (unsigned)-1) |
95cc27f0 | 285 | printf(", anchor %u", s->anchor.nr); |
70224baa | 286 | if (s->rule.nr != (unsigned)-1) |
95cc27f0 JS |
287 | printf(", rule %u", s->rule.nr); |
288 | if (s->src_node != NULL) | |
289 | printf(", source-track"); | |
290 | if (s->nat_src_node != NULL) | |
291 | printf(", sticky-address"); | |
292 | printf("\n"); | |
293 | } | |
294 | if (opts & PF_OPT_VERBOSE2) { | |
70224baa JL |
295 | printf(" id: %016llx creatorid: %08x%s\n", |
296 | (unsigned long long)be64toh(s->id), ntohl(s->creatorid), | |
297 | ((s->sync_flags & PFSTATE_NOSYNC) ? " (no-sync)" : "")); | |
95cc27f0 JS |
298 | } |
299 | } | |
300 | ||
301 | int | |
302 | unmask(struct pf_addr *m, sa_family_t af __unused) | |
303 | { | |
304 | int i = 31, j = 0, b = 0; | |
305 | u_int32_t tmp; | |
306 | ||
307 | while (j < 4 && m->addr32[j] == 0xffffffff) { | |
308 | b += 32; | |
309 | j++; | |
310 | } | |
311 | if (j < 4) { | |
312 | tmp = ntohl(m->addr32[j]); | |
313 | for (i = 31; tmp & (1 << i); --i) | |
314 | b++; | |
315 | } | |
316 | return (b); | |
317 | } |