xref: /openbsd-src/usr.sbin/tcpdump/pf_print_state.c (revision 92bb59a8a81491a73f30855c5fc819f868a56f2c)
1*92bb59a8Skevlo /*	$OpenBSD: pf_print_state.c,v 1.14 2018/09/07 07:49:43 kevlo Exp $	*/
2231a0e50Scanacar 
3231a0e50Scanacar /*
4231a0e50Scanacar  * Copyright (c) 2001 Daniel Hartmeier
5231a0e50Scanacar  * All rights reserved.
6231a0e50Scanacar  *
7231a0e50Scanacar  * Redistribution and use in source and binary forms, with or without
8231a0e50Scanacar  * modification, are permitted provided that the following conditions
9231a0e50Scanacar  * are met:
10231a0e50Scanacar  *
11231a0e50Scanacar  *    - Redistributions of source code must retain the above copyright
12231a0e50Scanacar  *      notice, this list of conditions and the following disclaimer.
13231a0e50Scanacar  *    - Redistributions in binary form must reproduce the above
14231a0e50Scanacar  *      copyright notice, this list of conditions and the following
15231a0e50Scanacar  *      disclaimer in the documentation and/or other materials provided
16231a0e50Scanacar  *      with the distribution.
17231a0e50Scanacar  *
18231a0e50Scanacar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19231a0e50Scanacar  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20231a0e50Scanacar  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21231a0e50Scanacar  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22231a0e50Scanacar  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23231a0e50Scanacar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24231a0e50Scanacar  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25231a0e50Scanacar  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26231a0e50Scanacar  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27231a0e50Scanacar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28231a0e50Scanacar  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29231a0e50Scanacar  * POSSIBILITY OF SUCH DAMAGE.
30231a0e50Scanacar  *
31231a0e50Scanacar  */
32231a0e50Scanacar 
33231a0e50Scanacar #include <sys/types.h>
34231a0e50Scanacar #include <sys/socket.h>
35231a0e50Scanacar #include <net/if.h>
36231a0e50Scanacar #define TCPSTATES
3752a421fcSderaadt #include <netinet/in.h>
38231a0e50Scanacar #include <netinet/tcp_fsm.h>
39231a0e50Scanacar #include <net/pfvar.h>
40231a0e50Scanacar #include <arpa/inet.h>
41231a0e50Scanacar #include <netdb.h>
42231a0e50Scanacar 
43231a0e50Scanacar #include <stdio.h>
44231a0e50Scanacar #include <string.h>
45c9ab7344Sjsg #include <vis.h>
46231a0e50Scanacar 
47231a0e50Scanacar #include "pfctl_parser.h"
48231a0e50Scanacar #include "pfctl.h"
49231a0e50Scanacar #include "addrtoname.h"
50231a0e50Scanacar 
51231a0e50Scanacar void	print_name(struct pf_addr *, sa_family_t);
52231a0e50Scanacar 
53231a0e50Scanacar void
print_addr(struct pf_addr_wrap * addr,sa_family_t af,int verbose)54231a0e50Scanacar print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
55231a0e50Scanacar {
56231a0e50Scanacar 	switch (addr->type) {
57231a0e50Scanacar 	case PF_ADDR_DYNIFTL:
58231a0e50Scanacar 		printf("(%s", addr->v.ifname);
59231a0e50Scanacar 		if (addr->iflags & PFI_AFLAG_NETWORK)
60231a0e50Scanacar 			printf(":network");
61231a0e50Scanacar 		if (addr->iflags & PFI_AFLAG_BROADCAST)
62231a0e50Scanacar 			printf(":broadcast");
63231a0e50Scanacar 		if (addr->iflags & PFI_AFLAG_PEER)
64231a0e50Scanacar 			printf(":peer");
65231a0e50Scanacar 		if (addr->iflags & PFI_AFLAG_NOALIAS)
66231a0e50Scanacar 			printf(":0");
67231a0e50Scanacar 		if (verbose) {
68231a0e50Scanacar 			if (addr->p.dyncnt <= 0)
69231a0e50Scanacar 				printf(":*");
70231a0e50Scanacar 			else
71231a0e50Scanacar 				printf(":%d", addr->p.dyncnt);
72231a0e50Scanacar 		}
73231a0e50Scanacar 		printf(")");
74231a0e50Scanacar 		break;
75231a0e50Scanacar 	case PF_ADDR_TABLE:
76231a0e50Scanacar 		if (verbose)
77231a0e50Scanacar 			if (addr->p.tblcnt == -1)
78231a0e50Scanacar 				printf("<%s:*>", addr->v.tblname);
79231a0e50Scanacar 			else
80231a0e50Scanacar 				printf("<%s:%d>", addr->v.tblname,
81231a0e50Scanacar 				    addr->p.tblcnt);
82231a0e50Scanacar 		else
83231a0e50Scanacar 			printf("<%s>", addr->v.tblname);
84231a0e50Scanacar 		return;
85231a0e50Scanacar 	case PF_ADDR_ADDRMASK:
86231a0e50Scanacar 		if (PF_AZERO(&addr->v.a.addr, AF_INET6) &&
87231a0e50Scanacar 		    PF_AZERO(&addr->v.a.mask, AF_INET6))
88231a0e50Scanacar 			printf("any");
89231a0e50Scanacar 		else {
90231a0e50Scanacar 			char buf[48];
91231a0e50Scanacar 
92231a0e50Scanacar 			if (inet_ntop(af, &addr->v.a.addr, buf,
93231a0e50Scanacar 			    sizeof(buf)) == NULL)
94231a0e50Scanacar 				printf("?");
95231a0e50Scanacar 			else
96231a0e50Scanacar 				printf("%s", buf);
97231a0e50Scanacar 		}
98231a0e50Scanacar 		break;
99231a0e50Scanacar 	case PF_ADDR_NOROUTE:
100231a0e50Scanacar 		printf("no-route");
101231a0e50Scanacar 		return;
102231a0e50Scanacar 	default:
103231a0e50Scanacar 		printf("?");
104231a0e50Scanacar 		return;
105231a0e50Scanacar 	}
106231a0e50Scanacar 	if (! PF_AZERO(&addr->v.a.mask, af)) {
107*92bb59a8Skevlo 		int bits = unmask(&addr->v.a.mask);
108231a0e50Scanacar 
109231a0e50Scanacar 		if (bits != (af == AF_INET ? 32 : 128))
110231a0e50Scanacar 			printf("/%d", bits);
111231a0e50Scanacar 	}
112231a0e50Scanacar }
113231a0e50Scanacar 
114231a0e50Scanacar void
print_name(struct pf_addr * addr,sa_family_t af)115231a0e50Scanacar print_name(struct pf_addr *addr, sa_family_t af)
116231a0e50Scanacar {
117231a0e50Scanacar 	char *host;
118231a0e50Scanacar 
119231a0e50Scanacar 	switch (af) {
120231a0e50Scanacar 	case AF_INET:
121231a0e50Scanacar 		host = getname((char *)&addr->v4);
122231a0e50Scanacar 		break;
123231a0e50Scanacar 	case AF_INET6:
124231a0e50Scanacar 		host = getname6((char *)&addr->v6);
125231a0e50Scanacar 		break;
126231a0e50Scanacar 	default:
127231a0e50Scanacar 		host = "?";
128231a0e50Scanacar 		break;
129231a0e50Scanacar 	}
130231a0e50Scanacar 	printf("%s", host);
131231a0e50Scanacar }
132231a0e50Scanacar 
133231a0e50Scanacar void
print_host(struct pf_addr * addr,u_int16_t port,sa_family_t af,u_int16_t rdom,const char * proto,int opts)134471800d7Sclaudio print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, u_int16_t rdom,
1353ef7fc25Slteo     const char *proto, int opts)
136231a0e50Scanacar {
1373ef7fc25Slteo 	struct servent	*s = NULL;
1383ef7fc25Slteo 	char		ps[6];
1393ef7fc25Slteo 
1407d3e2ec5Sclaudio 	if (rdom)
141471800d7Sclaudio 		printf("(%u) ", ntohs(rdom));
1427d3e2ec5Sclaudio 
143231a0e50Scanacar 	if (opts & PF_OPT_USEDNS)
144195fbb45Smcbride 		print_name(addr, af);
145231a0e50Scanacar 	else {
146231a0e50Scanacar 		struct pf_addr_wrap aw;
147231a0e50Scanacar 
148231a0e50Scanacar 		memset(&aw, 0, sizeof(aw));
149195fbb45Smcbride 		aw.v.a.addr = *addr;
150231a0e50Scanacar 		if (af == AF_INET)
151231a0e50Scanacar 			aw.v.a.mask.addr32[0] = 0xffffffff;
152231a0e50Scanacar 		else {
153231a0e50Scanacar 			memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
154231a0e50Scanacar 			af = AF_INET6;
155231a0e50Scanacar 		}
156231a0e50Scanacar 		print_addr(&aw, af, opts & PF_OPT_VERBOSE2);
157231a0e50Scanacar 	}
158231a0e50Scanacar 
159195fbb45Smcbride 	if (port) {
1603ef7fc25Slteo 		snprintf(ps, sizeof(ps), "%u", ntohs(port));
1613ef7fc25Slteo 		if (opts & PF_OPT_PORTNAMES)
1623ef7fc25Slteo 			s = getservbyport(port, proto);
163231a0e50Scanacar 		if (af == AF_INET)
1643ef7fc25Slteo 			printf(":%s", s ? s->s_name : ps);
165231a0e50Scanacar 		else
1663ef7fc25Slteo 			printf("[%s]", s ? s->s_name : ps);
167231a0e50Scanacar 	}
168231a0e50Scanacar }
169231a0e50Scanacar 
170231a0e50Scanacar void
print_seq(struct pfsync_state_peer * p)17197ffb19eSmcbride print_seq(struct pfsync_state_peer *p)
172231a0e50Scanacar {
173231a0e50Scanacar 	if (p->seqdiff)
17497ffb19eSmcbride 		printf("[%u + %u](+%u)", ntohl(p->seqlo),
17597ffb19eSmcbride 		    ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff));
176231a0e50Scanacar 	else
17797ffb19eSmcbride 		printf("[%u + %u]", ntohl(p->seqlo),
17897ffb19eSmcbride 		    ntohl(p->seqhi) - ntohl(p->seqlo));
179231a0e50Scanacar }
180231a0e50Scanacar 
181231a0e50Scanacar void
print_state(struct pfsync_state * s,int opts)18297ffb19eSmcbride print_state(struct pfsync_state *s, int opts)
183231a0e50Scanacar {
18497ffb19eSmcbride 	struct pfsync_state_peer *src, *dst;
185195fbb45Smcbride 	struct pfsync_state_key *sk, *nk;
186c9ab7344Sjsg 	char ifname[IFNAMSIZ * 4 + 1];
187c9ab7344Sjsg 	int min, sec, sidx, didx, i;
188c9ab7344Sjsg 	char *cp = ifname;
189231a0e50Scanacar 
190231a0e50Scanacar 	if (s->direction == PF_OUT) {
191231a0e50Scanacar 		src = &s->src;
192231a0e50Scanacar 		dst = &s->dst;
193195fbb45Smcbride 		sk = &s->key[PF_SK_STACK];
194195fbb45Smcbride 		nk = &s->key[PF_SK_WIRE];
195195fbb45Smcbride 		if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
196195fbb45Smcbride 			sk->port[0] = nk->port[0];
197231a0e50Scanacar 	} else {
198231a0e50Scanacar 		src = &s->dst;
199231a0e50Scanacar 		dst = &s->src;
200195fbb45Smcbride 		sk = &s->key[PF_SK_WIRE];
201195fbb45Smcbride 		nk = &s->key[PF_SK_STACK];
202195fbb45Smcbride 		if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
203195fbb45Smcbride 			sk->port[1] = nk->port[1];
204231a0e50Scanacar 	}
205c9ab7344Sjsg 	/* Treat s->ifname as untrusted input. */
206c9ab7344Sjsg 	for (i = 0; i < IFNAMSIZ && s->ifname[i] != '\0'; i++)
207c9ab7344Sjsg 		cp = vis(cp, s->ifname[i], VIS_WHITE, 0);
208c9ab7344Sjsg 	printf("%s ", ifname);
209231a0e50Scanacar 	printf("%s ", ipproto_string(s->proto));
210195fbb45Smcbride 
211d25344e8Sclaudio 	if (nk->af != sk->af)
212d25344e8Sclaudio 		sidx = 1, didx = 0;
213d25344e8Sclaudio 	else
214d25344e8Sclaudio 		sidx = 0, didx = 1;
215d25344e8Sclaudio 
2163ef7fc25Slteo 	print_host(&nk->addr[didx], nk->port[didx], nk->af, nk->rdomain, NULL, opts);
217d25344e8Sclaudio 	if (nk->af != sk->af || PF_ANEQ(&nk->addr[1], &sk->addr[1], nk->af) ||
218195fbb45Smcbride 	    nk->port[1] != sk->port[1]) {
219195fbb45Smcbride 		printf(" (");
220d25344e8Sclaudio 		print_host(&sk->addr[1], sk->port[1], sk->af, sk->rdomain,
2213ef7fc25Slteo 		    NULL, opts);
222195fbb45Smcbride 		printf(")");
223231a0e50Scanacar 	}
224231a0e50Scanacar 	if (s->direction == PF_OUT)
225231a0e50Scanacar 		printf(" -> ");
226231a0e50Scanacar 	else
227231a0e50Scanacar 		printf(" <- ");
2283ef7fc25Slteo 	print_host(&nk->addr[sidx], nk->port[sidx], nk->af, nk->rdomain, NULL,
2293ef7fc25Slteo 	    opts);
230d25344e8Sclaudio 	if (nk->af != sk->af || PF_ANEQ(&nk->addr[0], &sk->addr[0], nk->af) ||
231195fbb45Smcbride 	    nk->port[0] != sk->port[0]) {
232195fbb45Smcbride 		printf(" (");
2333ef7fc25Slteo 		print_host(&sk->addr[0], sk->port[0], sk->af, sk->rdomain, NULL,
234d25344e8Sclaudio 		    opts);
235195fbb45Smcbride 		printf(")");
236195fbb45Smcbride 	}
237231a0e50Scanacar 
238231a0e50Scanacar 	printf("    ");
239231a0e50Scanacar 	if (s->proto == IPPROTO_TCP) {
240231a0e50Scanacar 		if (src->state <= TCPS_TIME_WAIT &&
241231a0e50Scanacar 		    dst->state <= TCPS_TIME_WAIT)
2429b7de3ccSmcbride 			printf("\n   %s:%s", tcpstates[src->state],
243231a0e50Scanacar 			    tcpstates[dst->state]);
244231a0e50Scanacar 		else if (src->state == PF_TCPS_PROXY_SRC ||
245231a0e50Scanacar 		    dst->state == PF_TCPS_PROXY_SRC)
2469b7de3ccSmcbride 			printf("\n   PROXY:SRC");
247231a0e50Scanacar 		else if (src->state == PF_TCPS_PROXY_DST ||
248231a0e50Scanacar 		    dst->state == PF_TCPS_PROXY_DST)
2499b7de3ccSmcbride 			printf("\n   PROXY:DST");
250231a0e50Scanacar 		else
2519b7de3ccSmcbride 			printf("\n   <BAD STATE LEVELS %u:%u>",
252231a0e50Scanacar 			    src->state, dst->state);
253231a0e50Scanacar 		if (opts & PF_OPT_VERBOSE) {
2549b7de3ccSmcbride 			printf("\n   ");
255231a0e50Scanacar 			print_seq(src);
256231a0e50Scanacar 			if (src->wscale && dst->wscale)
257231a0e50Scanacar 				printf(" wscale %u",
258231a0e50Scanacar 				    src->wscale & PF_WSCALE_MASK);
259231a0e50Scanacar 			printf("  ");
260231a0e50Scanacar 			print_seq(dst);
261231a0e50Scanacar 			if (src->wscale && dst->wscale)
262231a0e50Scanacar 				printf(" wscale %u",
263231a0e50Scanacar 				    dst->wscale & PF_WSCALE_MASK);
264231a0e50Scanacar 		}
265231a0e50Scanacar 	} else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES &&
266231a0e50Scanacar 	    dst->state < PFUDPS_NSTATES) {
267231a0e50Scanacar 		const char *states[] = PFUDPS_NAMES;
268231a0e50Scanacar 
2699b7de3ccSmcbride 		printf("   %s:%s", states[src->state], states[dst->state]);
270231a0e50Scanacar 	} else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES &&
271231a0e50Scanacar 	    dst->state < PFOTHERS_NSTATES) {
272231a0e50Scanacar 		/* XXX ICMP doesn't really have state levels */
273231a0e50Scanacar 		const char *states[] = PFOTHERS_NAMES;
274231a0e50Scanacar 
2759b7de3ccSmcbride 		printf("   %s:%s", states[src->state], states[dst->state]);
276231a0e50Scanacar 	} else {
2779b7de3ccSmcbride 		printf("   %u:%u", src->state, dst->state);
278231a0e50Scanacar 	}
279231a0e50Scanacar 
280231a0e50Scanacar 	if (opts & PF_OPT_VERBOSE) {
28197ffb19eSmcbride 		u_int64_t packets[2];
28297ffb19eSmcbride 		u_int64_t bytes[2];
28325c4ae05Smpf 		u_int32_t creation = ntohl(s->creation);
284c62efabcSdlg 		u_int32_t expire = ntohl(s->expire);
28597ffb19eSmcbride 
28625c4ae05Smpf 		sec = creation % 60;
28725c4ae05Smpf 		creation /= 60;
28825c4ae05Smpf 		min = creation % 60;
28925c4ae05Smpf 		creation /= 60;
29025c4ae05Smpf 		printf("\n   age %.2u:%.2u:%.2u", creation, min, sec);
291c62efabcSdlg 		sec = expire % 60;
292c62efabcSdlg 		expire /= 60;
293c62efabcSdlg 		min = expire % 60;
294c62efabcSdlg 		expire /= 60;
295c62efabcSdlg 		printf(", expires in %.2u:%.2u:%.2u", expire, min, sec);
29697ffb19eSmcbride 
29797ffb19eSmcbride 		bcopy(s->packets[0], &packets[0], sizeof(u_int64_t));
29897ffb19eSmcbride 		bcopy(s->packets[1], &packets[1], sizeof(u_int64_t));
29997ffb19eSmcbride 		bcopy(s->bytes[0], &bytes[0], sizeof(u_int64_t));
30097ffb19eSmcbride 		bcopy(s->bytes[1], &bytes[1], sizeof(u_int64_t));
301b19e9e6fSmcbride 		printf(", %llu:%llu pkts, %llu:%llu bytes",
30297ffb19eSmcbride 		    betoh64(packets[0]),
30397ffb19eSmcbride 		    betoh64(packets[1]),
30497ffb19eSmcbride 		    betoh64(bytes[0]),
30597ffb19eSmcbride 		    betoh64(bytes[1]));
30697ffb19eSmcbride 		if (s->anchor != -1)
30797ffb19eSmcbride 			printf(", anchor %u", ntohl(s->anchor));
30897ffb19eSmcbride 		if (s->rule != -1)
30997ffb19eSmcbride 			printf(", rule %u", ntohl(s->rule));
310231a0e50Scanacar 	}
311231a0e50Scanacar 	if (opts & PF_OPT_VERBOSE2) {
31297ffb19eSmcbride 		u_int64_t id;
31397ffb19eSmcbride 
31497ffb19eSmcbride 		bcopy(&s->id, &id, sizeof(u_int64_t));
3159b7de3ccSmcbride 		printf("\n   id: %016llx creatorid: %08x",
31697ffb19eSmcbride 		    betoh64(id), ntohl(s->creatorid));
317231a0e50Scanacar 	}
318231a0e50Scanacar }
319231a0e50Scanacar 
320231a0e50Scanacar int
unmask(struct pf_addr * m)321*92bb59a8Skevlo unmask(struct pf_addr *m)
322231a0e50Scanacar {
323231a0e50Scanacar 	int i = 31, j = 0, b = 0;
324231a0e50Scanacar 	u_int32_t tmp;
325231a0e50Scanacar 
326231a0e50Scanacar 	while (j < 4 && m->addr32[j] == 0xffffffff) {
327231a0e50Scanacar 		b += 32;
328231a0e50Scanacar 		j++;
329231a0e50Scanacar 	}
330231a0e50Scanacar 	if (j < 4) {
331231a0e50Scanacar 		tmp = ntohl(m->addr32[j]);
332231a0e50Scanacar 		for (i = 31; tmp & (1 << i); --i)
333231a0e50Scanacar 			b++;
334231a0e50Scanacar 	}
335231a0e50Scanacar 	return (b);
336231a0e50Scanacar }
337