1 /*	$NetBSD: pf_print_state.c,v 1.1 2010/12/05 05:11:30 christos Exp $	*/
2 /*	$OpenBSD: pf_print_state.c,v 1.45 2007/05/31 04:13:37 mcbride Exp $	*/
3 
4 /*
5  * Copyright (c) 2001 Daniel Hartmeier
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  *    - Redistributions of source code must retain the above copyright
13  *      notice, this list of conditions and the following disclaimer.
14  *    - Redistributions in binary form must reproduce the above
15  *      copyright notice, this list of conditions and the following
16  *      disclaimer in the documentation and/or other materials provided
17  *      with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __RCSID("$NetBSD: pf_print_state.c,v 1.1 2010/12/05 05:11:30 christos Exp $");
37 #endif
38 
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <net/if.h>
46 #define TCPSTATES
47 #include <netinet/tcp_fsm.h>
48 #include <net/pfvar.h>
49 #include <arpa/inet.h>
50 #include <netdb.h>
51 
52 #include <stdio.h>
53 #include <string.h>
54 
55 #include "pfctl_parser.h"
56 #include "pfctl.h"
57 
58 void	print_name(struct pf_addr *, sa_family_t);
59 
60 void
61 print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
62 {
63 	switch (addr->type) {
64 	case PF_ADDR_DYNIFTL:
65 		printf("(%s", addr->v.ifname);
66 		if (addr->iflags & PFI_AFLAG_NETWORK)
67 			printf(":network");
68 		if (addr->iflags & PFI_AFLAG_BROADCAST)
69 			printf(":broadcast");
70 		if (addr->iflags & PFI_AFLAG_PEER)
71 			printf(":peer");
72 		if (addr->iflags & PFI_AFLAG_NOALIAS)
73 			printf(":0");
74 		if (verbose) {
75 			if (addr->p.dyncnt <= 0)
76 				printf(":*");
77 			else
78 				printf(":%d", addr->p.dyncnt);
79 		}
80 		printf(")");
81 		break;
82 	case PF_ADDR_TABLE:
83 		if (verbose)
84 			if (addr->p.tblcnt == -1)
85 				printf("<%s:*>", addr->v.tblname);
86 			else
87 				printf("<%s:%d>", addr->v.tblname,
88 				    addr->p.tblcnt);
89 		else
90 			printf("<%s>", addr->v.tblname);
91 		return;
92 	case PF_ADDR_ADDRMASK:
93 		if (PF_AZERO(&addr->v.a.addr, AF_INET6) &&
94 		    PF_AZERO(&addr->v.a.mask, AF_INET6))
95 			printf("any");
96 		else {
97 			char buf[48];
98 
99 			if (inet_ntop(af, &addr->v.a.addr, buf,
100 			    sizeof(buf)) == NULL)
101 				printf("?");
102 			else
103 				printf("%s", buf);
104 		}
105 		break;
106 	case PF_ADDR_NOROUTE:
107 		printf("no-route");
108 		return;
109 	case PF_ADDR_URPFFAILED:
110 		printf("urpf-failed");
111 		return;
112 	case PF_ADDR_RTLABEL:
113 		printf("route \"%s\"", addr->v.rtlabelname);
114 		return;
115 	default:
116 		printf("?");
117 		return;
118 	}
119 
120 	/* mask if not _both_ address and mask are zero */
121 	if (!(PF_AZERO(&addr->v.a.addr, AF_INET6) &&
122 	    PF_AZERO(&addr->v.a.mask, AF_INET6))) {
123 		int bits = unmask(&addr->v.a.mask, af);
124 
125 		if (bits != (af == AF_INET ? 32 : 128))
126 			printf("/%d", bits);
127 	}
128 }
129 
130 void
131 print_name(struct pf_addr *addr, sa_family_t af)
132 {
133 	char host[NI_MAXHOST];
134 
135 	strlcpy(host, "?", sizeof(host));
136 	switch (af) {
137 	case AF_INET: {
138 		struct sockaddr_in sin;
139 
140 		memset(&sin, 0, sizeof(sin));
141 		sin.sin_len = sizeof(sin);
142 		sin.sin_family = AF_INET;
143 		sin.sin_addr = addr->v4;
144 		getnameinfo((struct sockaddr *)&sin, sin.sin_len,
145 		    host, sizeof(host), NULL, 0, NI_NOFQDN);
146 		break;
147 	}
148 	case AF_INET6: {
149 		struct sockaddr_in6 sin6;
150 
151 		memset(&sin6, 0, sizeof(sin6));
152 		sin6.sin6_len = sizeof(sin6);
153 		sin6.sin6_family = AF_INET6;
154 		sin6.sin6_addr = addr->v6;
155 		getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
156 		    host, sizeof(host), NULL, 0, NI_NOFQDN);
157 		break;
158 	}
159 	}
160 	printf("%s", host);
161 }
162 
163 void
164 print_host(struct pfsync_state_host *h, sa_family_t af, int opts)
165 {
166 	u_int16_t p = ntohs(h->port);
167 
168 	if (opts & PF_OPT_USEDNS)
169 		print_name(&h->addr, af);
170 	else {
171 		struct pf_addr_wrap aw;
172 
173 		memset(&aw, 0, sizeof(aw));
174 		aw.v.a.addr = h->addr;
175 		if (af == AF_INET)
176 			aw.v.a.mask.addr32[0] = 0xffffffff;
177 		else {
178 			memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
179 			af = AF_INET6;
180 		}
181 		print_addr(&aw, af, opts & PF_OPT_VERBOSE2);
182 	}
183 
184 	if (p) {
185 		if (af == AF_INET)
186 			printf(":%u", p);
187 		else
188 			printf("[%u]", p);
189 	}
190 }
191 
192 void
193 print_seq(struct pfsync_state_peer *p)
194 {
195 	if (p->seqdiff)
196 		printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo,
197 		    p->seqdiff);
198 	else
199 		printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo);
200 }
201 
202 void
203 print_state(struct pfsync_state *s, int opts)
204 {
205 	struct pfsync_state_peer *src, *dst;
206 	struct protoent *p;
207 	int min, sec;
208 
209 	if (s->direction == PF_OUT) {
210 		src = &s->src;
211 		dst = &s->dst;
212 	} else {
213 		src = &s->dst;
214 		dst = &s->src;
215 	}
216 	printf("%s ", s->ifname);
217 	if ((p = getprotobynumber(s->proto)) != NULL)
218 		printf("%s ", p->p_name);
219 	else
220 		printf("%u ", s->proto);
221 	if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) ||
222 	    (s->lan.port != s->gwy.port)) {
223 		print_host(&s->lan, s->af, opts);
224 		if (s->direction == PF_OUT)
225 			printf(" -> ");
226 		else
227 			printf(" <- ");
228 	}
229 	print_host(&s->gwy, s->af, opts);
230 	if (s->direction == PF_OUT)
231 		printf(" -> ");
232 	else
233 		printf(" <- ");
234 	print_host(&s->ext, s->af, opts);
235 
236 	printf("    ");
237 	if (s->proto == IPPROTO_TCP) {
238 		if (src->state <= TCPS_TIME_WAIT &&
239 		    dst->state <= TCPS_TIME_WAIT)
240 			printf("   %s:%s\n", tcpstates[src->state],
241 			    tcpstates[dst->state]);
242 		else if (src->state == PF_TCPS_PROXY_SRC ||
243 		    dst->state == PF_TCPS_PROXY_SRC)
244 			printf("   PROXY:SRC\n");
245 		else if (src->state == PF_TCPS_PROXY_DST ||
246 		    dst->state == PF_TCPS_PROXY_DST)
247 			printf("   PROXY:DST\n");
248 		else
249 			printf("   <BAD STATE LEVELS %u:%u>\n",
250 			    src->state, dst->state);
251 		if (opts & PF_OPT_VERBOSE) {
252 			printf("   ");
253 			print_seq(src);
254 			if (src->wscale && dst->wscale)
255 				printf(" wscale %u",
256 				    src->wscale & PF_WSCALE_MASK);
257 			printf("  ");
258 			print_seq(dst);
259 			if (src->wscale && dst->wscale)
260 				printf(" wscale %u",
261 				    dst->wscale & PF_WSCALE_MASK);
262 			printf("\n");
263 		}
264 	} else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES &&
265 	    dst->state < PFUDPS_NSTATES) {
266 		const char *states[] = PFUDPS_NAMES;
267 
268 		printf("   %s:%s\n", states[src->state], states[dst->state]);
269 	} else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES &&
270 	    dst->state < PFOTHERS_NSTATES) {
271 		/* XXX ICMP doesn't really have state levels */
272 		const char *states[] = PFOTHERS_NAMES;
273 
274 		printf("   %s:%s\n", states[src->state], states[dst->state]);
275 	} else {
276 		printf("   %u:%u\n", src->state, dst->state);
277 	}
278 
279 	if (opts & PF_OPT_VERBOSE) {
280 		sec = s->creation % 60;
281 		s->creation /= 60;
282 		min = s->creation % 60;
283 		s->creation /= 60;
284 		printf("   age %.2u:%.2u:%.2u", s->creation, min, sec);
285 		sec = s->expire % 60;
286 		s->expire /= 60;
287 		min = s->expire % 60;
288 		s->expire /= 60;
289 		printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec);
290 		printf(", %llu:%llu pkts, %llu:%llu bytes",
291 		    (unsigned long long)pf_state_counter_from_pfsync(s->packets[0]),
292 		    (unsigned long long)pf_state_counter_from_pfsync(s->packets[1]),
293 		    (unsigned long long)pf_state_counter_from_pfsync(s->bytes[0]),
294 		    (unsigned long long)pf_state_counter_from_pfsync(s->bytes[1]));
295 		if (s->anchor != -1)
296 			printf(", anchor %u", s->anchor);
297 		if (s->rule != -1)
298 			printf(", rule %u", s->rule);
299 		if (s->sync_flags & PFSYNC_FLAG_SRCNODE)
300 			printf(", source-track");
301 		if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE)
302 			printf(", sticky-address");
303 		printf("\n");
304 	}
305 	if (opts & PF_OPT_VERBOSE2) {
306 		printf("   id: %016llx creatorid: %08x%s\n",
307 		    (unsigned long long int)pf_state_counter_from_pfsync(s->id),
308 		    ntohl(s->creatorid),
309 		    ((s->sync_flags & PFSTATE_NOSYNC) ? " (no-sync)" : ""));
310 	}
311 }
312 
313 int
314 unmask(struct pf_addr *m, sa_family_t af)
315 {
316 	int i = 31, j = 0, b = 0;
317 	u_int32_t tmp;
318 
319 	while (j < 4 && m->addr32[j] == 0xffffffff) {
320 		b += 32;
321 		j++;
322 	}
323 	if (j < 4) {
324 		tmp = ntohl(m->addr32[j]);
325 		for (i = 31; tmp & (1 << i); --i)
326 			b++;
327 	}
328 	return (b);
329 }
330