xref: /openbsd-src/sbin/pfctl/pfctl_parser.c (revision 8445c53715e7030056b779e8ab40efb7820981f2)
1 /*	$OpenBSD: pfctl_parser.c,v 1.50 2001/09/15 23:23:40 wilfried Exp $ */
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 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <net/if.h>
36 #include <netinet/in.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/ip.h>
39 #include <netinet/ip_icmp.h>
40 #include <netinet/icmp6.h>
41 #define TCPSTATES
42 #include <netinet/tcp_fsm.h>
43 #include <net/pfvar.h>
44 #include <arpa/inet.h>
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <netdb.h>
51 #include <stdarg.h>
52 #include <errno.h>
53 #include <err.h>
54 
55 #include "pfctl_parser.h"
56 
57 int		 unmask (struct pf_addr *, int);
58 void		 print_addr (struct pf_addr *, struct pf_addr *, int);
59 void		 print_host (struct pf_state_host *, int);
60 void		 print_seq (struct pf_state_peer *);
61 void		 print_port (u_int8_t, u_int16_t, u_int16_t, char *);
62 void		 print_flags (u_int8_t);
63 
64 char *tcpflags = "FSRPAU";
65 
66 struct icmptypeent icmp_type[] = {
67 	{ "echoreq",	ICMP_ECHO },
68 	{ "echorep",	ICMP_ECHOREPLY },
69 	{ "unreach",	ICMP_UNREACH },
70 	{ "squench",	ICMP_SOURCEQUENCH },
71 	{ "redir",	ICMP_REDIRECT },
72 	{ "althost",	ICMP_ALTHOSTADDR },
73 	{ "routeradv",	ICMP_ROUTERADVERT },
74 	{ "routersol",	ICMP_ROUTERSOLICIT },
75 	{ "timex",	ICMP_TIMXCEED },
76 	{ "paramprob",	ICMP_PARAMPROB },
77 	{ "timereq",	ICMP_TSTAMP },
78 	{ "timerep",	ICMP_TSTAMPREPLY },
79 	{ "inforeq",	ICMP_IREQ },
80 	{ "inforep",	ICMP_IREQREPLY },
81 	{ "maskreq",	ICMP_MASKREQ },
82 	{ "maskrep",	ICMP_MASKREPLY },
83 	{ "trace",	ICMP_TRACEROUTE },
84 	{ "dataconv",	ICMP_DATACONVERR },
85 	{ "mobredir",	ICMP_MOBILE_REDIRECT },
86 	{ "ipv6-where",	ICMP_IPV6_WHEREAREYOU },
87 	{ "ipv6-here",	ICMP_IPV6_IAMHERE },
88 	{ "mobregreq",	ICMP_MOBILE_REGREQUEST },
89 	{ "mobregrep",	ICMP_MOBILE_REGREPLY },
90 	{ "skip",	ICMP_SKIP },
91 	{ "photuris",	ICMP_PHOTURIS }
92 
93 };
94 
95 struct icmptypeent icmp6_type[] = {
96 	{ "unreach",	ICMP6_DST_UNREACH },
97 	{ "toobig",	ICMP6_PACKET_TOO_BIG },
98 	{ "timex",	ICMP6_TIME_EXCEEDED },
99 	{ "paramprob",	ICMP6_PARAM_PROB },
100 	{ "echoreq",	ICMP6_ECHO_REQUEST },
101 	{ "echorep",	ICMP6_ECHO_REPLY },
102 	{ "groupqry",	ICMP6_MEMBERSHIP_QUERY },
103 	{ "listqry",	MLD6_LISTENER_QUERY },
104 	{ "grouprep",	ICMP6_MEMBERSHIP_REPORT },
105 	{ "listenrep",	MLD6_LISTENER_REPORT },
106 	{ "groupterm",	ICMP6_MEMBERSHIP_REDUCTION },
107 	{ "listendone", MLD6_LISTENER_DONE },
108 	{ "routersol",	ND_ROUTER_SOLICIT },
109 	{ "routeradv",	ND_ROUTER_ADVERT },
110 	{ "neighbrsol", ND_NEIGHBOR_SOLICIT },
111 	{ "neighbradv", ND_NEIGHBOR_ADVERT },
112 	{ "redir",	ND_REDIRECT },
113 	{ "routrrenum", ICMP6_ROUTER_RENUMBERING },
114 	{ "wrureq",	ICMP6_WRUREQUEST },
115 	{ "wrurep",	ICMP6_WRUREPLY },
116 	{ "fqdnreq",	ICMP6_FQDN_QUERY },
117 	{ "fqdnrep",	ICMP6_FQDN_REPLY },
118 	{ "niqry",	ICMP6_NI_QUERY },
119 	{ "nirep",	ICMP6_NI_REPLY },
120 	{ "mtraceresp",	MLD6_MTRACE_RESP },
121 	{ "mtrace",	MLD6_MTRACE }
122 };
123 
124 struct icmpcodeent icmp_code[] = {
125 	{ "net-unr",		ICMP_UNREACH,	ICMP_UNREACH_NET },
126 	{ "host-unr",		ICMP_UNREACH,	ICMP_UNREACH_HOST },
127 	{ "proto-unr",		ICMP_UNREACH,	ICMP_UNREACH_PROTOCOL },
128 	{ "port-unr",		ICMP_UNREACH,	ICMP_UNREACH_PORT },
129 	{ "needfrag",		ICMP_UNREACH,	ICMP_UNREACH_NEEDFRAG },
130 	{ "srcfail",		ICMP_UNREACH,	ICMP_UNREACH_SRCFAIL },
131 	{ "net-unk",		ICMP_UNREACH,	ICMP_UNREACH_NET_UNKNOWN },
132 	{ "host-unk",		ICMP_UNREACH,	ICMP_UNREACH_HOST_UNKNOWN },
133 	{ "isolate",		ICMP_UNREACH,	ICMP_UNREACH_ISOLATED },
134 	{ "net-prohib",		ICMP_UNREACH,	ICMP_UNREACH_NET_PROHIB },
135 	{ "host-prohib",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PROHIB },
136 	{ "net-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSNET },
137 	{ "host-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSHOST },
138 	{ "filter-prohib",	ICMP_UNREACH,	ICMP_UNREACH_FILTER_PROHIB },
139 	{ "host-preced",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PRECEDENCE },
140 	{ "cutoff-preced",	ICMP_UNREACH,	ICMP_UNREACH_PRECEDENCE_CUTOFF },
141 	{ "redir-net",		ICMP_REDIRECT,	ICMP_REDIRECT_NET },
142 	{ "redir-host",		ICMP_REDIRECT,	ICMP_REDIRECT_HOST },
143 	{ "redir-tos-net",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSNET },
144 	{ "redir-tos-host",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSHOST },
145 	{ "normal-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
146 	{ "common-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
147 	{ "transit",		ICMP_TIMXCEED,	ICMP_TIMXCEED_INTRANS },
148 	{ "reassemb",		ICMP_TIMXCEED,	ICMP_TIMXCEED_REASS },
149 	{ "badhead",		ICMP_PARAMPROB,	ICMP_PARAMPROB_ERRATPTR },
150 	{ "optmiss",		ICMP_PARAMPROB,	ICMP_PARAMPROB_OPTABSENT },
151 	{ "badlen",		ICMP_PARAMPROB,	ICMP_PARAMPROB_LENGTH },
152 	{ "unknown-ind",	ICMP_PHOTURIS,	ICMP_PHOTURIS_UNKNOWN_INDEX },
153 	{ "auth-fail",		ICMP_PHOTURIS,	ICMP_PHOTURIS_AUTH_FAILED },
154 	{ "decrypt-fail",	ICMP_PHOTURIS,	ICMP_PHOTURIS_DECRYPT_FAILED }
155 };
156 
157 struct icmpcodeent icmp6_code[] = {
158 	{ "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
159 	{ "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
160 	{ "notnbr-unr",	ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR },
161 	{ "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
162 	{ "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
163 	{ "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
164 	{ "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
165 	{ "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
166 	{ "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
167 	{ "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
168 	{ "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
169 	{ "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER }
170 };
171 
172 
173 struct icmptypeent *
174 geticmptypebynumber(u_int8_t type, u_int8_t af)
175 {
176 	unsigned i;
177 
178 	if (af != AF_INET6) {
179 		for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) {
180 			if(type == icmp_type[i].type)
181 				return (&icmp_type[i]);
182 		}
183 	} else {
184 		for(i=0; i < (sizeof (icmp6_type) /
185 		    sizeof(icmp6_type[0])); i++) {
186 			if(type == icmp6_type[i].type)
187 				 return (&icmp6_type[i]);
188 		}
189 	}
190 	return (NULL);
191 }
192 
193 struct icmptypeent *
194 geticmptypebyname(char *w, u_int8_t af)
195 {
196 	unsigned i;
197 
198 	if (af != AF_INET6) {
199 		for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) {
200 			if(!strcmp(w, icmp_type[i].name))
201 				return (&icmp_type[i]);
202 		}
203 	} else {
204 		for(i=0; i < (sizeof (icmp6_type) /
205 		    sizeof(icmp6_type[0])); i++) {
206 			if(!strcmp(w, icmp6_type[i].name))
207 				return (&icmp6_type[i]);
208 		}
209 	}
210 	return (NULL);
211 }
212 
213 struct icmpcodeent *
214 geticmpcodebynumber(u_int8_t type, u_int8_t code, u_int8_t af)
215 {
216 	unsigned i;
217 
218 	if (af != AF_INET6) {
219 		for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) {
220 			if (type == icmp_code[i].type &&
221 			    code == icmp_code[i].code)
222 				return (&icmp_code[i]);
223 		}
224 	} else {
225 		for(i=0; i < (sizeof (icmp6_code) /
226 		   sizeof(icmp6_code[0])); i++) {
227 			if (type == icmp6_code[i].type &&
228 			    code == icmp6_code[i].code)
229 				return (&icmp6_code[i]);
230 		}
231 	}
232 	return (NULL);
233 }
234 
235 struct icmpcodeent *
236 geticmpcodebyname(u_long type, char *w, u_int8_t af)
237 {
238 	unsigned i;
239 
240 	if (af != AF_INET6) {
241 		for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) {
242 			if (type == icmp_code[i].type &&
243 			    !strcmp(w, icmp_code[i].name))
244 				return (&icmp_code[i]);
245 		}
246 	} else {
247 		for(i=0; i < (sizeof (icmp6_code) /
248 		    sizeof(icmp6_code[0])); i++) {
249 			if (type == icmp6_code[i].type &&
250 			    !strcmp(w, icmp6_code[i].name))
251 				return (&icmp6_code[i]);
252 		}
253 	}
254 	return (NULL);
255 }
256 
257 int
258 unmask(struct pf_addr *m, int af)
259 {
260 	int i = 31, j = 0, b = 0, msize;
261 	u_int32_t tmp;
262 
263 	if (af == AF_INET)
264 		msize = 1;
265 	else
266 		msize = 4;
267 	while (j < msize && m->addr32[j] == 0xffffffff) {
268 			b += 32;
269 			j++;
270 	}
271 	if (j < msize) {
272 		tmp = ntohl(m->addr32[j]);
273 		for (i = 31; tmp & (1 << i); --i)
274 			b++;
275 	}
276 	return (b);
277 }
278 
279 void
280 print_addr(struct pf_addr *addr, struct pf_addr *mask, int af)
281 {
282 	char buf[48];
283 	const char *bf;
284 
285 	bf = inet_ntop(af, addr, buf, sizeof(buf));
286 	printf("%s", bf);
287 	if (mask != NULL) {
288 		if (!PF_AZERO(mask, af))
289 			printf("/%u", unmask(mask, af));
290 	}
291 }
292 
293 void
294 print_host(struct pf_state_host *h, int af)
295 {
296 	u_int16_t p = ntohs(h->port);
297 
298 	print_addr(&h->addr, NULL, af);
299 	if (af == AF_INET)
300 		printf(":%u", p);
301 	else
302 		printf("[%u]", p);
303 }
304 
305 
306 void
307 print_seq(struct pf_state_peer *p)
308 {
309 	if (p->seqdiff)
310 		printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo,
311 		    p->seqdiff);
312 	else
313 		printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo);
314 }
315 
316 void
317 print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
318 {
319 	struct servent *s = getservbyport(p1, proto);
320 
321 	p1 = ntohs(p1);
322 	p2 = ntohs(p2);
323 	printf("port ");
324 	if (op == PF_OP_IRG)
325 		printf("%u >< %u ", p1, p2);
326 	else if (op == PF_OP_XRG)
327 		printf("%u <> %u ", p1, p2);
328 	else if (op == PF_OP_EQ) {
329 		if (s != NULL)
330 			printf("= %s ", s->s_name);
331 		else
332 			printf("= %u ", p1);
333 	} else if (op == PF_OP_NE) {
334 		if (s != NULL)
335 			printf("!= %s ", s->s_name);
336 		else
337 			printf("!= %u ", p1);
338 	} else if (op == PF_OP_LT)
339 		printf("< %u ", p1);
340 	else if (op == PF_OP_LE)
341 		printf("<= %u ", p1);
342 	else if (op == PF_OP_GT)
343 		printf("> %u ", p1);
344 	else if (op == PF_OP_GE)
345 		printf(">= %u ", p1);
346 }
347 
348 void
349 print_flags(u_int8_t f)
350 {
351 	int i;
352 
353 	for (i = 0; i < 6; ++i)
354 		if (f & (1 << i))
355 			printf("%c", tcpflags[i]);
356 }
357 
358 void
359 print_nat(struct pf_nat *n)
360 {
361 	printf("@nat ");
362 	if (n->ifname[0]) {
363 		printf("on ");
364 		if (n->ifnot)
365 			printf("! ");
366 		printf("%s ", n->ifname);
367 	}
368 	printf("from ");
369 	if (!PF_AZERO(&n->saddr, n->af) || !PF_AZERO(&n->smask, n->af)) {
370 		if (n->snot)
371 			printf("! ");
372 		print_addr(&n->saddr, &n->smask, n->af);
373 		printf(" ");
374 	} else
375 		printf("any ");
376 	printf("to ");
377 	if (!PF_AZERO(&n->daddr, n->af) || !PF_AZERO(&n->dmask, n->af)) {
378 		if (n->snot)
379 			printf("! ");
380 		print_addr(&n->daddr, &n->dmask, n->af);
381 		printf(" ");
382 	} else
383 		printf("any ");
384 	printf("-> ");
385 	print_addr(&n->raddr, NULL, n->af);
386 	printf(" ");
387 	switch (n->proto) {
388 	case IPPROTO_TCP:
389 		printf("proto tcp");
390 		break;
391 	case IPPROTO_UDP:
392 		printf("proto udp");
393 		break;
394 	case IPPROTO_ICMP:
395 		printf("proto icmp");
396 		break;
397 	}
398 	printf("\n");
399 }
400 
401 void
402 print_binat(struct pf_binat *b)
403 {
404 	printf("@binat ");
405 	if (b->ifname[0]) {
406 		printf("on ");
407 		printf("%s ", b->ifname);
408 	}
409 	switch (b->proto) {
410 	case IPPROTO_TCP:
411 		printf("proto tcp ");
412 		break;
413 	case IPPROTO_UDP:
414 		printf("proto udp ");
415 		break;
416 	case IPPROTO_ICMP:
417 		printf("proto icmp ");
418 		break;
419 	}
420 	printf("from ");
421 	print_addr(&b->saddr, NULL, b->af);
422 	printf(" ");
423 	printf("to ");
424 	if (!PF_AZERO(&b->daddr, b->af) || !PF_AZERO(&b->dmask, b->af)) {
425 		if (b->dnot)
426 			printf("! ");
427 		print_addr(&b->daddr, &b->dmask, b->af);
428 		printf(" ");
429 	} else
430 		printf("any ");
431  	printf("-> ");
432 	print_addr(&b->raddr, NULL, b->af);
433 	printf("\n");
434 }
435 
436 void
437 print_rdr(struct pf_rdr *r)
438 {
439 	printf("@rdr ");
440 	if (r->ifname[0]) {
441 		printf("on ");
442 		if (r->ifnot)
443 			printf("! ");
444 		printf("%s ", r->ifname);
445 	}
446 	switch (r->proto) {
447 	case IPPROTO_TCP:
448 		printf("proto tcp ");
449 		break;
450 	case IPPROTO_UDP:
451 		printf("proto udp ");
452 		break;
453 	}
454 	printf("from ");
455 	if (!PF_AZERO(&r->saddr, r->af) || !PF_AZERO(&r->smask, r->af)) {
456 		if (r->snot)
457 			printf("! ");
458 		print_addr(&r->saddr, &r->smask, r->af);
459 		printf(" ");
460 	} else
461 		printf("any ");
462 	printf("to ");
463 	if (!PF_AZERO(&r->daddr, r->af) || !PF_AZERO(&r->dmask, r->af)) {
464 		if (r->snot)
465 			printf("! ");
466 		print_addr(&r->daddr, &r->dmask, r->af);
467 		printf(" ");
468 	} else
469 		printf("any ");
470 	printf("port %u", ntohs(r->dport));
471 	if (r->opts & PF_DPORT_RANGE)
472 		printf(":%u", ntohs(r->dport2));
473 	printf(" -> ");
474 	print_addr(&r->raddr, NULL, r->af);
475 	printf(" ");
476 	printf("port %u", ntohs(r->rport));
477 	if (r->opts & PF_RPORT_RANGE)
478 		printf(":*");
479 	printf("\n");
480 }
481 
482 char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
483 char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
484 
485 void
486 print_status(struct pf_status *s)
487 {
488 
489 	time_t t = time(NULL);
490 	int i;
491 
492 	printf("Status: %s  Time: %u  Since: %u  Debug: ",
493 	    s->running ? "Enabled" : "Disabled",
494 	    t, s->since);
495 	switch (s->debug) {
496 		case 0:
497 			printf("None");
498 			break;
499 		case 1:
500 			printf("Urgent");
501 			break;
502 		case 2:
503 			printf("Misc");
504 			break;
505 	}
506 	printf("\nBytes In IPv4: %-10llu  Bytes Out: %-10llu\n",
507 	    s->bcounters[0][PF_IN], s->bcounters[0][PF_OUT]);
508 	printf("         IPv6: %-10llu  Bytes Out: %-10llu\n",
509 	    s->bcounters[1][PF_IN], s->bcounters[1][PF_OUT]);
510 	printf("Inbound Packets IPv4:  Passed: %-10llu  Dropped: %-10llu\n",
511 	    s->pcounters[0][PF_IN][PF_PASS],
512 	    s->pcounters[0][PF_IN][PF_DROP]);
513 	printf("                IPv6:  Passed: %-10llu  Dropped: %-10llu\n",
514 	    s->pcounters[1][PF_IN][PF_PASS],
515 	    s->pcounters[1][PF_IN][PF_DROP]);
516 	printf("Outbound Packets IPv4: Passed: %-10llu  Dropped: %-10llu\n",
517 	    s->pcounters[0][PF_OUT][PF_PASS],
518 	    s->pcounters[0][PF_OUT][PF_DROP]);
519 	printf("                 IPv6: Passed: %-10llu  Dropped: %-10llu\n",
520 	    s->pcounters[1][PF_OUT][PF_PASS],
521 	    s->pcounters[1][PF_OUT][PF_DROP]);
522 	printf("States: %u\n", s->states);
523 	printf("pf Counters\n");
524 	for (i = 0; i < FCNT_MAX; i++)
525 		printf("%-25s %-8lld\n", pf_fcounters[i],
526 		    s->fcounters[i]);
527 	printf("Counters\n");
528 	for (i = 0; i < PFRES_MAX; i++)
529 		printf("%-25s %-8lld\n", pf_reasons[i],
530 		    s->counters[i]);
531 }
532 
533 void
534 print_state(struct pf_state *s)
535 {
536 	struct pf_state_peer *src, *dst;
537 	u_int8_t hrs, min, sec;
538 
539 	if (s->direction == PF_OUT) {
540 		src = &s->src;
541 		dst = &s->dst;
542 	} else {
543 		src = &s->dst;
544 		dst = &s->src;
545 	}
546 	switch (s->proto) {
547 	case IPPROTO_TCP:
548 		printf("TCP  ");
549 		break;
550 	case IPPROTO_UDP:
551 		printf("UDP  ");
552 		break;
553 	case IPPROTO_ICMPV6:
554 	case IPPROTO_ICMP:
555 		printf("ICMP ");
556 		break;
557 	default:
558 		printf("???? ");
559 		break;
560 	}
561 	if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) ||
562 	    (s->lan.port != s->gwy.port)) {
563 		print_host(&s->lan, s->af);
564 		if (s->direction == PF_OUT)
565 			printf(" -> ");
566 		else
567 			printf(" <- ");
568 	}
569 	print_host(&s->gwy, s->af);
570 	if (s->direction == PF_OUT)
571 		printf(" -> ");
572 	else
573 		printf(" <- ");
574 	print_host(&s->ext, s->af);
575 
576 	printf("    ");
577 	if (s->proto == IPPROTO_TCP) {
578 		if (src->state <= TCPS_TIME_WAIT &&
579 		    dst->state <= TCPS_TIME_WAIT) {
580 			printf("   %s:%s\n", tcpstates[src->state],
581 			    tcpstates[dst->state]);
582 		} else {
583 			printf("   <BAD STATE LEVELS>\n");
584 		}
585 		printf("   ");
586 		print_seq(src);
587 		printf("  ");
588 		print_seq(dst);
589 		printf("\n");
590 	} else {
591 		printf("   %u:%u\n", src->state, dst->state);
592 	}
593 
594 	sec = s->creation % 60;
595 	s->creation /= 60;
596 	min = s->creation % 60;
597 	s->creation /= 60;
598 	hrs = s->creation;
599 	printf("   age %.2u:%.2u:%.2u", hrs, min, sec);
600 	sec = s->expire % 60;
601 	s->expire /= 60;
602 	min = s->expire % 60;
603 	s->expire /= 60;
604 	hrs = s->expire;
605 	printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec);
606 	printf(", %u pkts, %u bytes\n", s->packets, s->bytes);
607 }
608 
609 void
610 print_rule(struct pf_rule *r)
611 {
612 	printf("@%d ", r->nr);
613 	if (r->action == PF_PASS)
614 		printf("pass ");
615 	else if (r->action == PF_DROP) {
616 		printf("block ");
617 		if (r->rule_flag & PFRULE_RETURNRST)
618 			printf("return-rst ");
619 		else if (r->return_icmp) {
620 			struct icmpcodeent *ic;
621 
622 			if (r->af != AF_INET6)
623 				printf("return-icmp");
624 			else
625 				printf("return-icmp6");
626 			ic = geticmpcodebynumber(r->return_icmp >> 8,
627 			    r->return_icmp & 255, r->af);
628 
629 			if (ic == NULL)
630 				printf("(%u) ", r->return_icmp & 255);
631 			else if ((r->af != AF_INET6 && ic->code != ICMP_UNREACH_PORT) ||
632 			    (r->af == AF_INET6 && ic->code != ICMP6_DST_UNREACH_NOPORT))
633 				printf("(%s) ", ic->name);
634 			else
635 				printf(" ");
636 		}
637 	} else
638 		printf("scrub ");
639 	if (r->direction == 0)
640 		printf("in ");
641 	else
642 		printf("out ");
643 	if (r->log == 1)
644 		printf("log ");
645 	else if (r->log == 2)
646 		printf("log-all ");
647 	if (r->quick)
648 		printf("quick ");
649 	if (r->ifname[0])
650 		printf("on %s ", r->ifname);
651 	if (r->af) {
652 		if (r->af == AF_INET)
653 			printf("inet ");
654 		else
655 			printf("inet6 ");
656 	}
657 	if (r->proto) {
658 		struct protoent *p = getprotobynumber(r->proto);
659 		if (p != NULL)
660 			printf("proto %s ", p->p_name);
661 		else
662 			printf("proto %u ", r->proto);
663 	}
664 	if (PF_AZERO(&r->src.addr, AF_INET6) &&
665 	    PF_AZERO(&r->src.mask, AF_INET6) &&
666 	    !r->src.port_op && PF_AZERO(&r->dst.addr, AF_INET6) &&
667 	    PF_AZERO(&r->dst.mask, AF_INET6) && !r->dst.port_op)
668 		printf("all ");
669 	else {
670 		printf("from ");
671 		if (PF_AZERO(&r->src.addr, AF_INET6) &&
672 		    PF_AZERO(&r->src.mask, AF_INET6))
673 			printf("any ");
674 		else {
675 			if (r->src.not)
676 				printf("! ");
677 			print_addr(&r->src.addr, &r->src.mask, r->af);
678 			printf(" ");
679 		}
680 		if (r->src.port_op)
681 			print_port(r->src.port_op, r->src.port[0],
682 			    r->src.port[1],
683 			    r->proto == IPPROTO_TCP ? "tcp" : "udp");
684 
685 		printf("to ");
686 		if (PF_AZERO(&r->dst.addr, AF_INET6) &&
687 		    PF_AZERO(&r->dst.mask, AF_INET6))
688 			printf("any ");
689 		else {
690 			if (r->dst.not)
691 				printf("! ");
692 			print_addr(&r->dst.addr, &r->dst.mask, r->af);
693 			printf(" ");
694 		}
695 		if (r->dst.port_op)
696 			print_port(r->dst.port_op, r->dst.port[0],
697 			    r->dst.port[1],
698 			    r->proto == IPPROTO_TCP ? "tcp" : "udp");
699 	}
700 	if (r->flags || r->flagset) {
701 		printf("flags ");
702 		print_flags(r->flags);
703 		printf("/");
704 		print_flags(r->flagset);
705 		printf(" ");
706 	}
707 	if (r->type) {
708 		struct icmptypeent *p;
709 
710 		p = geticmptypebynumber(r->type-1, r->af);
711 		if (r->af != AF_INET6)
712 			printf("icmp-type");
713 		else
714 			printf("ipv6-icmp-type");
715 		if (p != NULL)
716 			printf(" %s ", p->name);
717 		else
718 			printf(" %u ", r->type-1);
719 		if (r->code) {
720 			struct icmpcodeent *p;
721 
722 			p = geticmpcodebynumber(r->type-1, r->code-1, r->af);
723 			if (p != NULL)
724 				printf("code %s ", p->name);
725 			else
726 				printf("code %u ", r->code-1);
727 		}
728 	}
729 	if (r->keep_state == PF_STATE_NORMAL)
730 		printf("keep state ");
731 	else if (r->keep_state == PF_STATE_MODULATE)
732 		printf("modulate state ");
733 	if (r->rule_flag & PFRULE_NODF)
734 		printf("no-df ");
735 	if (r->min_ttl)
736 		printf("min-ttl %d ", r->min_ttl);
737 
738 	printf("\n");
739 }
740 
741 int
742 parse_flags(char *s)
743 {
744 	char *p, *q;
745 	u_int8_t f = 0;
746 
747 	for (p = s; *p; p++) {
748 		if ((q = strchr(tcpflags, *p)) == NULL)
749 			return -1;
750 		else
751 			f |= 1 << (q - tcpflags);
752 	}
753 	return (f ? f : 63);
754 }
755