xref: /openbsd-src/sbin/pfctl/pfctl_parser.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*	$OpenBSD: pfctl_parser.c,v 1.56 2001/12/10 18:08:12 dhartmei 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 (p) {
300 		if (af == AF_INET)
301 			printf(":%u", p);
302 		else
303 			printf("[%u]", p);
304 	}
305 }
306 
307 
308 void
309 print_seq(struct pf_state_peer *p)
310 {
311 	if (p->seqdiff)
312 		printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo,
313 		    p->seqdiff);
314 	else
315 		printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo);
316 }
317 
318 void
319 print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
320 {
321 	struct servent *s = getservbyport(p1, proto);
322 
323 	p1 = ntohs(p1);
324 	p2 = ntohs(p2);
325 	printf("port ");
326 	if (op == PF_OP_IRG)
327 		printf("%u >< %u ", p1, p2);
328 	else if (op == PF_OP_XRG)
329 		printf("%u <> %u ", p1, p2);
330 	else if (op == PF_OP_EQ) {
331 		if (s != NULL)
332 			printf("= %s ", s->s_name);
333 		else
334 			printf("= %u ", p1);
335 	} else if (op == PF_OP_NE) {
336 		if (s != NULL)
337 			printf("!= %s ", s->s_name);
338 		else
339 			printf("!= %u ", p1);
340 	} else if (op == PF_OP_LT)
341 		printf("< %u ", p1);
342 	else if (op == PF_OP_LE)
343 		printf("<= %u ", p1);
344 	else if (op == PF_OP_GT)
345 		printf("> %u ", p1);
346 	else if (op == PF_OP_GE)
347 		printf(">= %u ", p1);
348 }
349 
350 void
351 print_flags(u_int8_t f)
352 {
353 	int i;
354 
355 	for (i = 0; i < 6; ++i)
356 		if (f & (1 << i))
357 			printf("%c", tcpflags[i]);
358 }
359 
360 void
361 print_nat(struct pf_nat *n)
362 {
363 	printf("@nat ");
364 	if (n->ifname[0]) {
365 		printf("on ");
366 		if (n->ifnot)
367 			printf("! ");
368 		printf("%s ", n->ifname);
369 	}
370 	if (n->proto) {
371 		struct protoent *p = getprotobynumber(n->proto);
372 		if (n != NULL)
373 			printf("proto %s ", p->p_name);
374 		else
375 			printf("proto %u ", n->proto);
376 	}
377 	printf("from ");
378 	if (!PF_AZERO(&n->saddr, n->af) || !PF_AZERO(&n->smask, n->af)) {
379 		if (n->snot)
380 			printf("! ");
381 		print_addr(&n->saddr, &n->smask, n->af);
382 		printf(" ");
383 	} else
384 		printf("any ");
385 	printf("to ");
386 	if (!PF_AZERO(&n->daddr, n->af) || !PF_AZERO(&n->dmask, n->af)) {
387 		if (n->dnot)
388 			printf("! ");
389 		print_addr(&n->daddr, &n->dmask, n->af);
390 		printf(" ");
391 	} else
392 		printf("any ");
393 	printf("-> ");
394 	print_addr(&n->raddr, NULL, n->af);
395 	printf("\n");
396 }
397 
398 void
399 print_binat(struct pf_binat *b)
400 {
401 	printf("@binat ");
402 	if (b->ifname[0]) {
403 		printf("on ");
404 		printf("%s ", b->ifname);
405 	}
406 	if (b->proto) {
407 		struct protoent *p = getprotobynumber(b->proto);
408 		if (p != NULL)
409 			printf("proto %s ", p->p_name);
410 		else
411 			printf("proto %u ", b->proto);
412 	}
413 	printf("from ");
414 	print_addr(&b->saddr, NULL, b->af);
415 	printf(" ");
416 	printf("to ");
417 	if (!PF_AZERO(&b->daddr, b->af) || !PF_AZERO(&b->dmask, b->af)) {
418 		if (b->dnot)
419 			printf("! ");
420 		print_addr(&b->daddr, &b->dmask, b->af);
421 		printf(" ");
422 	} else
423 		printf("any ");
424  	printf("-> ");
425 	print_addr(&b->raddr, NULL, b->af);
426 	printf("\n");
427 }
428 
429 void
430 print_rdr(struct pf_rdr *r)
431 {
432 	printf("@rdr ");
433 	if (r->ifname[0]) {
434 		printf("on ");
435 		if (r->ifnot)
436 			printf("! ");
437 		printf("%s ", r->ifname);
438 	}
439 	if (r->proto) {
440 		struct protoent *p = getprotobynumber(r->proto);
441 		if (p != NULL)
442 			printf("proto %s ", p->p_name);
443 		else
444 			printf("proto %u ", r->proto);
445 	}
446 	printf("from ");
447 	if (!PF_AZERO(&r->saddr, r->af) || !PF_AZERO(&r->smask, r->af)) {
448 		if (r->snot)
449 			printf("! ");
450 		print_addr(&r->saddr, &r->smask, r->af);
451 		printf(" ");
452 	} else
453 		printf("any ");
454 	printf("to ");
455 	if (!PF_AZERO(&r->daddr, r->af) || !PF_AZERO(&r->dmask, r->af)) {
456 		if (r->dnot)
457 			printf("! ");
458 		print_addr(&r->daddr, &r->dmask, r->af);
459 		printf(" ");
460 	} else
461 		printf("any ");
462 	if (r->dport) {
463 		printf("port %u", ntohs(r->dport));
464 		if (r->opts & PF_DPORT_RANGE)
465 			printf(":%u", ntohs(r->dport2));
466 	}
467 	printf(" -> ");
468 	print_addr(&r->raddr, NULL, r->af);
469 	printf(" ");
470 	if (r->rport) {
471 		printf("port %u", ntohs(r->rport));
472 		if (r->opts & PF_RPORT_RANGE)
473 			printf(":*");
474 	}
475 	printf("\n");
476 }
477 
478 char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
479 char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
480 
481 void
482 print_status(struct pf_status *s)
483 {
484 
485 	time_t t = time(NULL);
486 	int i;
487 
488 	printf("Status: %s  Time: %u  Since: %u  Debug: ",
489 	    s->running ? "Enabled" : "Disabled",
490 	    t, s->since);
491 	switch (s->debug) {
492 		case 0:
493 			printf("None");
494 			break;
495 		case 1:
496 			printf("Urgent");
497 			break;
498 		case 2:
499 			printf("Misc");
500 			break;
501 	}
502 	printf("\nBytes In IPv4: %-10llu  Bytes Out: %-10llu\n",
503 	    s->bcounters[0][PF_IN], s->bcounters[0][PF_OUT]);
504 	printf("         IPv6: %-10llu  Bytes Out: %-10llu\n",
505 	    s->bcounters[1][PF_IN], s->bcounters[1][PF_OUT]);
506 	printf("Inbound Packets IPv4:  Passed: %-10llu  Dropped: %-10llu\n",
507 	    s->pcounters[0][PF_IN][PF_PASS],
508 	    s->pcounters[0][PF_IN][PF_DROP]);
509 	printf("                IPv6:  Passed: %-10llu  Dropped: %-10llu\n",
510 	    s->pcounters[1][PF_IN][PF_PASS],
511 	    s->pcounters[1][PF_IN][PF_DROP]);
512 	printf("Outbound Packets IPv4: Passed: %-10llu  Dropped: %-10llu\n",
513 	    s->pcounters[0][PF_OUT][PF_PASS],
514 	    s->pcounters[0][PF_OUT][PF_DROP]);
515 	printf("                 IPv6: Passed: %-10llu  Dropped: %-10llu\n",
516 	    s->pcounters[1][PF_OUT][PF_PASS],
517 	    s->pcounters[1][PF_OUT][PF_DROP]);
518 	printf("States: %u\n", s->states);
519 	printf("pf Counters\n");
520 	for (i = 0; i < FCNT_MAX; i++)
521 		printf("%-25s %-8lld\n", pf_fcounters[i],
522 		    s->fcounters[i]);
523 	printf("Counters\n");
524 	for (i = 0; i < PFRES_MAX; i++)
525 		printf("%-25s %-8lld\n", pf_reasons[i],
526 		    s->counters[i]);
527 }
528 
529 void
530 print_state(struct pf_state *s, int opts)
531 {
532 	struct pf_state_peer *src, *dst;
533 	struct protoent *p;
534 	u_int8_t hrs, min, sec;
535 
536 	if (s->direction == PF_OUT) {
537 		src = &s->src;
538 		dst = &s->dst;
539 	} else {
540 		src = &s->dst;
541 		dst = &s->src;
542 	}
543 	if ((p = getprotobynumber(s->proto)) != NULL)
544 		printf("%s ", p->p_name);
545 	else
546 		printf("%u ", s->proto);
547 	if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) ||
548 	    (s->lan.port != s->gwy.port)) {
549 		print_host(&s->lan, s->af);
550 		if (s->direction == PF_OUT)
551 			printf(" -> ");
552 		else
553 			printf(" <- ");
554 	}
555 	print_host(&s->gwy, s->af);
556 	if (s->direction == PF_OUT)
557 		printf(" -> ");
558 	else
559 		printf(" <- ");
560 	print_host(&s->ext, s->af);
561 
562 	printf("    ");
563 	if (s->proto == IPPROTO_TCP) {
564 		if (src->state <= TCPS_TIME_WAIT &&
565 		    dst->state <= TCPS_TIME_WAIT) {
566 			printf("   %s:%s\n", tcpstates[src->state],
567 			    tcpstates[dst->state]);
568 		} else {
569 			printf("   <BAD STATE LEVELS>\n");
570 		}
571 		if (opts & PF_OPT_VERBOSE) {
572 			printf("   ");
573 			print_seq(src);
574 			printf("  ");
575 			print_seq(dst);
576 			printf("\n");
577 		}
578 	} else {
579 		printf("   %u:%u\n", src->state, dst->state);
580 	}
581 
582 	if (opts & PF_OPT_VERBOSE) {
583 		sec = s->creation % 60;
584 		s->creation /= 60;
585 		min = s->creation % 60;
586 		s->creation /= 60;
587 		hrs = s->creation;
588 		printf("   age %.2u:%.2u:%.2u", hrs, min, sec);
589 		sec = s->expire % 60;
590 		s->expire /= 60;
591 		min = s->expire % 60;
592 		s->expire /= 60;
593 		hrs = s->expire;
594 		printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec);
595 		printf(", %u pkts, %u bytes\n", s->packets, s->bytes);
596 	}
597 }
598 
599 void
600 print_rule(struct pf_rule *r)
601 {
602 	printf("@%d ", r->nr);
603 	if (r->action == PF_PASS)
604 		printf("pass ");
605 	else if (r->action == PF_DROP) {
606 		printf("block ");
607 		if (r->rule_flag & PFRULE_RETURNRST)
608 			printf("return-rst ");
609 		else if (r->return_icmp) {
610 			struct icmpcodeent *ic;
611 
612 			if (r->af != AF_INET6)
613 				printf("return-icmp");
614 			else
615 				printf("return-icmp6");
616 			ic = geticmpcodebynumber(r->return_icmp >> 8,
617 			    r->return_icmp & 255, r->af);
618 
619 			if (ic == NULL)
620 				printf("(%u) ", r->return_icmp & 255);
621 			else if ((r->af != AF_INET6 && ic->code != ICMP_UNREACH_PORT) ||
622 			    (r->af == AF_INET6 && ic->code != ICMP6_DST_UNREACH_NOPORT))
623 				printf("(%s) ", ic->name);
624 			else
625 				printf(" ");
626 		}
627 	} else
628 		printf("scrub ");
629 	if (r->direction == 0)
630 		printf("in ");
631 	else
632 		printf("out ");
633 	if (r->log == 1)
634 		printf("log ");
635 	else if (r->log == 2)
636 		printf("log-all ");
637 	if (r->quick)
638 		printf("quick ");
639 	if (r->ifname[0])
640 		printf("on %s ", r->ifname);
641 	if (r->rt) {
642 		if (r->rt == PF_ROUTETO)
643 			printf("route-to ");
644 		else if (r->rt == PF_DUPTO)
645 			printf("dup-to ");
646 		else if (r->rt == PF_FASTROUTE)
647 			printf("fastroute");
648 		if (r->rt_ifname[0])
649 			printf("%s", r->rt_ifname);
650 		if (r->af && !PF_AZERO(&r->rt_addr, r->af)) {
651 			printf(":");
652 			print_addr(&r->rt_addr, NULL, r->af);
653 		}
654 		printf(" ");
655 	}
656 	if (r->af) {
657 		if (r->af == AF_INET)
658 			printf("inet ");
659 		else
660 			printf("inet6 ");
661 	}
662 	if (r->proto) {
663 		struct protoent *p = getprotobynumber(r->proto);
664 		if (p != NULL)
665 			printf("proto %s ", p->p_name);
666 		else
667 			printf("proto %u ", r->proto);
668 	}
669 	if (PF_AZERO(&r->src.addr, AF_INET6) &&
670 	    PF_AZERO(&r->src.mask, AF_INET6) &&
671 	    !r->src.port_op && PF_AZERO(&r->dst.addr, AF_INET6) &&
672 	    PF_AZERO(&r->dst.mask, AF_INET6) && !r->dst.port_op)
673 		printf("all ");
674 	else {
675 		printf("from ");
676 		if (PF_AZERO(&r->src.addr, AF_INET6) &&
677 		    PF_AZERO(&r->src.mask, AF_INET6))
678 			printf("any ");
679 		else {
680 			if (r->src.not)
681 				printf("! ");
682 			print_addr(&r->src.addr, &r->src.mask, r->af);
683 			printf(" ");
684 		}
685 		if (r->src.port_op)
686 			print_port(r->src.port_op, r->src.port[0],
687 			    r->src.port[1],
688 			    r->proto == IPPROTO_TCP ? "tcp" : "udp");
689 
690 		printf("to ");
691 		if (PF_AZERO(&r->dst.addr, AF_INET6) &&
692 		    PF_AZERO(&r->dst.mask, AF_INET6))
693 			printf("any ");
694 		else {
695 			if (r->dst.not)
696 				printf("! ");
697 			print_addr(&r->dst.addr, &r->dst.mask, r->af);
698 			printf(" ");
699 		}
700 		if (r->dst.port_op)
701 			print_port(r->dst.port_op, r->dst.port[0],
702 			    r->dst.port[1],
703 			    r->proto == IPPROTO_TCP ? "tcp" : "udp");
704 	}
705 	if (r->flags || r->flagset) {
706 		printf("flags ");
707 		print_flags(r->flags);
708 		printf("/");
709 		print_flags(r->flagset);
710 		printf(" ");
711 	}
712 	if (r->type) {
713 		struct icmptypeent *p;
714 
715 		p = geticmptypebynumber(r->type-1, r->af);
716 		if (r->af != AF_INET6)
717 			printf("icmp-type");
718 		else
719 			printf("ipv6-icmp-type");
720 		if (p != NULL)
721 			printf(" %s ", p->name);
722 		else
723 			printf(" %u ", r->type-1);
724 		if (r->code) {
725 			struct icmpcodeent *p;
726 
727 			p = geticmpcodebynumber(r->type-1, r->code-1, r->af);
728 			if (p != NULL)
729 				printf("code %s ", p->name);
730 			else
731 				printf("code %u ", r->code-1);
732 		}
733 	}
734 	if (r->keep_state == PF_STATE_NORMAL)
735 		printf("keep state ");
736 	else if (r->keep_state == PF_STATE_MODULATE)
737 		printf("modulate state ");
738 	if (r->rule_flag & PFRULE_NODF)
739 		printf("no-df ");
740 	if (r->min_ttl)
741 		printf("min-ttl %d ", r->min_ttl);
742 	if (r->allow_opts)
743 		printf("allow-opts ");
744 
745 	printf("\n");
746 }
747 
748 int
749 parse_flags(char *s)
750 {
751 	char *p, *q;
752 	u_int8_t f = 0;
753 
754 	for (p = s; *p; p++) {
755 		if ((q = strchr(tcpflags, *p)) == NULL)
756 			return -1;
757 		else
758 			f |= 1 << (q - tcpflags);
759 	}
760 	return (f ? f : 63);
761 }
762