xref: /openbsd-src/sbin/pfctl/pfctl_parser.c (revision 2badd5e3f47d2d4252969cd98d7042b4e701b5ac)
1 /*	$OpenBSD: pfctl_parser.c,v 1.44 2001/08/23 04:10:51 deraadt 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 #define TCPSTATES
41 #include <netinet/tcp_fsm.h>
42 #include <net/pfvar.h>
43 #include <arpa/inet.h>
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49 #include <netdb.h>
50 #include <stdarg.h>
51 #include <errno.h>
52 #include <err.h>
53 
54 #include "pfctl_parser.h"
55 
56 void		 print_addr (u_int32_t);
57 void		 print_host (struct pf_state_host *);
58 void		 print_seq (struct pf_state_peer *);
59 void		 print_port (u_int8_t, u_int16_t, u_int16_t, char *);
60 void		 print_flags (u_int8_t);
61 
62 char *tcpflags = "FSRPAU";
63 
64 struct icmptypeent icmp_type[] = {
65 	{ "echoreq",	ICMP_ECHO },
66 	{ "echorep",	ICMP_ECHOREPLY },
67 	{ "unreach",	ICMP_UNREACH },
68 	{ "squench",	ICMP_SOURCEQUENCH },
69 	{ "redir",	ICMP_REDIRECT },
70 	{ "althost",	ICMP_ALTHOSTADDR },
71 	{ "routeradv",	ICMP_ROUTERADVERT },
72 	{ "routersol",	ICMP_ROUTERSOLICIT },
73 	{ "timex",	ICMP_TIMXCEED },
74 	{ "paramprob",	ICMP_PARAMPROB },
75 	{ "timereq",	ICMP_TSTAMP },
76 	{ "timerep",	ICMP_TSTAMPREPLY },
77 	{ "inforeq",	ICMP_IREQ },
78 	{ "inforep",	ICMP_IREQREPLY },
79 	{ "maskreq",	ICMP_MASKREQ },
80 	{ "maskrep",	ICMP_MASKREPLY },
81 	{ "trace",	ICMP_TRACEROUTE },
82 	{ "dataconv",	ICMP_DATACONVERR },
83 	{ "mobredir",	ICMP_MOBILE_REDIRECT },
84 	{ "ipv6-where",	ICMP_IPV6_WHEREAREYOU },
85 	{ "ipv6-here",	ICMP_IPV6_IAMHERE },
86 	{ "mobregreq",	ICMP_MOBILE_REGREQUEST },
87 	{ "mobregrep",	ICMP_MOBILE_REGREPLY },
88 	{ "skip",	ICMP_SKIP },
89 	{ "photuris",	ICMP_PHOTURIS }
90 
91 };
92 
93 struct icmpcodeent icmp_code[] = {
94 	{ "net-unr",		ICMP_UNREACH,	ICMP_UNREACH_NET },
95 	{ "host-unr",		ICMP_UNREACH,	ICMP_UNREACH_HOST },
96 	{ "proto-unr",		ICMP_UNREACH,	ICMP_UNREACH_PROTOCOL },
97 	{ "port-unr",		ICMP_UNREACH,	ICMP_UNREACH_PORT },
98 	{ "needfrag",		ICMP_UNREACH,	ICMP_UNREACH_NEEDFRAG },
99 	{ "srcfail",		ICMP_UNREACH,	ICMP_UNREACH_SRCFAIL },
100 	{ "net-unk",		ICMP_UNREACH,	ICMP_UNREACH_NET_UNKNOWN },
101 	{ "host-unk",		ICMP_UNREACH,	ICMP_UNREACH_HOST_UNKNOWN },
102 	{ "isolate",		ICMP_UNREACH,	ICMP_UNREACH_ISOLATED },
103 	{ "net-prohib",		ICMP_UNREACH,	ICMP_UNREACH_NET_PROHIB },
104 	{ "host-prohib",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PROHIB },
105 	{ "net-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSNET },
106 	{ "host-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSHOST },
107 	{ "filter-prohib",	ICMP_UNREACH,	ICMP_UNREACH_FILTER_PROHIB },
108 	{ "host-preced",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PRECEDENCE },
109 	{ "cutoff-preced",	ICMP_UNREACH,	ICMP_UNREACH_PRECEDENCE_CUTOFF },
110 	{ "redir-net",		ICMP_REDIRECT,	ICMP_REDIRECT_NET },
111 	{ "redir-host",		ICMP_REDIRECT,	ICMP_REDIRECT_HOST },
112 	{ "redir-tos-net",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSNET },
113 	{ "redir-tos-host",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSHOST },
114 	{ "normal-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
115 	{ "common-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
116 	{ "transit",		ICMP_TIMXCEED,	ICMP_TIMXCEED_INTRANS },
117 	{ "reassemb",		ICMP_TIMXCEED,	ICMP_TIMXCEED_REASS },
118 	{ "badhead",		ICMP_PARAMPROB,	ICMP_PARAMPROB_ERRATPTR },
119 	{ "optmiss",		ICMP_PARAMPROB,	ICMP_PARAMPROB_OPTABSENT },
120 	{ "badlen",		ICMP_PARAMPROB,	ICMP_PARAMPROB_LENGTH },
121 	{ "unknown-ind",	ICMP_PHOTURIS,	ICMP_PHOTURIS_UNKNOWN_INDEX },
122 	{ "auth-fail",		ICMP_PHOTURIS,	ICMP_PHOTURIS_AUTH_FAILED },
123 	{ "decrypt-fail",	ICMP_PHOTURIS,	ICMP_PHOTURIS_DECRYPT_FAILED }
124 };
125 
126 struct icmptypeent *
127 geticmptypebynumber(u_int8_t type)
128 {
129 	unsigned i;
130 
131 	for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) {
132 		if(type == icmp_type[i].type)
133 			return (&icmp_type[i]);
134 	}
135 	return (0);
136 }
137 
138 struct icmptypeent *
139 geticmptypebyname(char *w)
140 {
141 	unsigned i;
142 
143 	for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) {
144 		if(!strcmp(w, icmp_type[i].name))
145 			return (&icmp_type[i]);
146 	}
147 	return (0);
148 }
149 
150 struct icmpcodeent *
151 geticmpcodebynumber(u_int8_t type, u_int8_t code)
152 {
153 	unsigned i;
154 
155 	for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) {
156 		if (type == icmp_code[i].type && code == icmp_code[i].code)
157 			return (&icmp_code[i]);
158 	}
159 	return (0);
160 }
161 
162 struct icmpcodeent *
163 geticmpcodebyname(u_long type, char *w)
164 {
165 	unsigned i;
166 
167 	for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) {
168 		if (type == icmp_code[i].type && !strcmp(w, icmp_code[i].name))
169 			return (&icmp_code[i]);
170 	}
171 	return (0);
172 }
173 
174 void
175 print_addr(u_int32_t a)
176 {
177 	a = ntohl(a);
178 	printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255);
179 }
180 
181 void
182 print_host(struct pf_state_host *h)
183 {
184 	u_int32_t a = ntohl(h->addr);
185 	u_int16_t p = ntohs(h->port);
186 
187 	printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, p);
188 }
189 
190 void
191 print_seq(struct pf_state_peer *p)
192 {
193 	printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo);
194 }
195 
196 void
197 print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
198 {
199 	struct servent *s = getservbyport(p1, proto);
200 
201 	p1 = ntohs(p1);
202 	p2 = ntohs(p2);
203 	printf("port ");
204 	if (op == PF_OP_IRG)
205 		printf("%u >< %u ", p1, p2);
206 	else if (op == PF_OP_XRG)
207 		printf("%u <> %u ", p1, p2);
208 	else if (op == PF_OP_EQ) {
209 		if (s != NULL)
210 			printf("= %s ", s->s_name);
211 		else
212 			printf("= %u ", p1);
213 	} else if (op == PF_OP_NE) {
214 		if (s != NULL)
215 			printf("!= %s ", s->s_name);
216 		else
217 			printf("!= %u ", p1);
218 	} else if (op == PF_OP_LT)
219 		printf("< %u ", p1);
220 	else if (op == PF_OP_LE)
221 		printf("<= %u ", p1);
222 	else if (op == PF_OP_GT)
223 		printf("> %u ", p1);
224 	else if (op == PF_OP_GE)
225 		printf(">= %u ", p1);
226 }
227 
228 void
229 print_flags(u_int8_t f)
230 {
231 	int i;
232 
233 	for (i = 0; i < 6; ++i)
234 		if (f & (1 << i))
235 			printf("%c", tcpflags[i]);
236 }
237 
238 void
239 print_nat(struct pf_nat *n)
240 {
241 	printf("@nat ");
242 	if (n->ifname[0]) {
243 		printf("on ");
244 		if (n->ifnot)
245 			printf("! ");
246 		printf("%s ", n->ifname);
247 	}
248 	printf("from ");
249 	if (n->saddr || n->smask) {
250 		if (n->snot)
251 			printf("! ");
252 		print_addr(n->saddr);
253 		if (n->smask != 0xFFFFFFFF) {
254 			printf("/");
255 			print_addr(n->smask);
256 		}
257 		printf(" ");
258 	} else
259 		printf("any ");
260 	printf("to ");
261 	if (n->daddr || n->dmask) {
262 		if (n->dnot)
263 			printf("! ");
264 		print_addr(n->daddr);
265 		if (n->dmask != 0xFFFFFFFF) {
266 			printf("/");
267 			print_addr(n->dmask);
268 		}
269 		printf(" ");
270 	} else
271 		printf("any ");
272 	printf("-> ");
273 	print_addr(n->raddr);
274 	printf(" ");
275 	switch (n->proto) {
276 	case IPPROTO_TCP:
277 		printf("proto tcp");
278 		break;
279 	case IPPROTO_UDP:
280 		printf("proto udp");
281 		break;
282 	case IPPROTO_ICMP:
283 		printf("proto icmp");
284 		break;
285 	}
286 	printf("\n");
287 }
288 
289 void
290 print_rdr(struct pf_rdr *r)
291 {
292 	printf("@rdr ");
293 	if (r->ifname[0]) {
294 		printf("on ");
295 		if (r->ifnot)
296 			printf("! ");
297 		printf("%s ", r->ifname);
298 	}
299 	switch (r->proto) {
300 	case IPPROTO_TCP:
301 		printf("proto tcp ");
302 		break;
303 	case IPPROTO_UDP:
304 		printf("proto udp ");
305 		break;
306 	}
307 	printf("from ");
308 	if (r->saddr || r->smask) {
309 		if (r->snot)
310 			printf("! ");
311 		print_addr(r->saddr);
312 		if (r->smask != 0xFFFFFFFF) {
313 			printf("/");
314 			print_addr(r->smask);
315 		}
316 		printf(" ");
317 	} else
318 		printf("any ");
319 	printf("to ");
320 	if (r->daddr || r->dmask) {
321 		if (r->dnot)
322 			printf("! ");
323 		print_addr(r->daddr);
324 		if (r->dmask != 0xFFFFFFFF) {
325 			printf("/");
326 			print_addr(r->dmask);
327 		}
328 		printf(" ");
329 	} else
330 		printf("any ");
331 	printf("port %u", ntohs(r->dport));
332 	if (r->opts & PF_DPORT_RANGE)
333 		printf(":%u", ntohs(r->dport2));
334 	printf(" -> ");
335 	print_addr(r->raddr);
336 	printf(" ");
337 	printf("port %u", ntohs(r->rport));
338 	if (r->opts & PF_RPORT_RANGE)
339 		printf(":*");
340 	printf("\n");
341 }
342 
343 char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
344 char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
345 
346 void
347 print_status(struct pf_status *s)
348 {
349 
350 	time_t t = time(NULL);
351 	int i;
352 
353 	printf("Status: %s  Time: %u  Since: %u  Debug: ",
354 	    s->running ? "Enabled" : "Disabled",
355 	    t, s->since);
356 	switch (s->debug) {
357 		case 0:
358 			printf("None");
359 			break;
360 		case 1:
361 			printf("Urgent");
362 			break;
363 		case 2:
364 			printf("Misc");
365 			break;
366 	}
367 	printf("\nBytes In: %-10llu  Bytes Out: %-10llu\n",
368 	    s->bcounters[PF_IN], s->bcounters[PF_OUT]);
369 	printf("Inbound Packets:  Passed: %-10llu  Dropped: %-10llu\n",
370 	    s->pcounters[PF_IN][PF_PASS],
371 	    s->pcounters[PF_IN][PF_DROP]);
372 	printf("Outbound Packets: Passed: %-10llu  Dropped: %-10llu\n",
373 	    s->pcounters[PF_OUT][PF_PASS],
374 	    s->pcounters[PF_OUT][PF_DROP]);
375 	printf("States: %u\n", s->states);
376 	printf("pf Counters\n");
377 	for (i = 0; i < FCNT_MAX; i++)
378 		printf("%-25s %-8lld\n", pf_fcounters[i],
379 		    s->fcounters[i]);
380 	printf("Counters\n");
381 	for (i = 0; i < PFRES_MAX; i++)
382 		printf("%-25s %-8lld\n", pf_reasons[i],
383 		    s->counters[i]);
384 }
385 
386 void
387 print_state(struct pf_state *s)
388 {
389 	struct pf_state_peer *src, *dst;
390 	u_int8_t hrs, min, sec;
391 
392 	if (s->direction == PF_OUT) {
393 		src = &s->src;
394 		dst = &s->dst;
395 	} else {
396 		src = &s->dst;
397 		dst = &s->src;
398 	}
399 	switch (s->proto) {
400 	case IPPROTO_TCP:
401 		printf("TCP  ");
402 		break;
403 	case IPPROTO_UDP:
404 		printf("UDP  ");
405 		break;
406 	case IPPROTO_ICMP:
407 		printf("ICMP ");
408 		break;
409 	default:
410 		printf("???? ");
411 		break;
412 	}
413 	if ((s->lan.addr != s->gwy.addr) || (s->lan.port != s->gwy.port)) {
414 		print_host(&s->lan);
415 		if (s->direction == PF_OUT)
416 			printf(" -> ");
417 		else
418 			printf(" <- ");
419 	}
420 	print_host(&s->gwy);
421 	if (s->direction == PF_OUT)
422 		printf(" -> ");
423 	else
424 		printf(" <- ");
425 	print_host(&s->ext);
426 	printf("\n");
427 
428 	if (s->proto == IPPROTO_TCP) {
429 		printf("   %s:%s  ", tcpstates[src->state],
430 			tcpstates[dst->state]);
431 		print_seq(src);
432 		printf("    ");
433 		print_seq(dst);
434 		printf("\n");
435 	} else {
436 		printf("   %u:%u  ", src->state, dst->state);
437 	}
438 
439 	sec = s->creation % 60;
440 	s->creation /= 60;
441 	min = s->creation % 60;
442 	s->creation /= 60;
443 	hrs = s->creation;
444 	printf("   age %.2u:%.2u:%.2u", hrs, min, sec);
445 	sec = s->expire % 60;
446 	s->expire /= 60;
447 	min = s->expire % 60;
448 	s->expire /= 60;
449 	hrs = s->expire;
450 	printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec);
451 	printf(", %u pkts, %u bytes\n", s->packets, s->bytes);
452 }
453 
454 void
455 print_rule(struct pf_rule *r)
456 {
457 	printf("@%d ", r->nr + 1);
458 	if (r->action == PF_PASS)
459 		printf("pass ");
460 	else if (r->action == PF_DROP) {
461 		printf("block ");
462 		if (r->rule_flag & PFRULE_RETURNRST)
463 			printf("return-rst ");
464 		else if (r->return_icmp) {
465 			struct icmpcodeent *ic;
466 
467 			printf("return-icmp");
468 			ic = geticmpcodebynumber(r->return_icmp >> 8,
469 			    r->return_icmp & 255);
470 			if ((ic == NULL) || (ic->type != ICMP_UNREACH))
471 				printf("(%u,%u) ", r->return_icmp >> 8,
472 				    r->return_icmp & 255);
473 			else if (ic->code != ICMP_UNREACH_PORT)
474 				printf("(%s) ", ic->name);
475 			else
476 				printf(" ");
477 		}
478 	} else
479 		printf("scrub ");
480 	if (r->direction == 0)
481 		printf("in ");
482 	else
483 		printf("out ");
484 	if (r->log == 1)
485 		printf("log ");
486 	else if (r->log == 2)
487 		printf("log-all ");
488 	if (r->quick)
489 		printf("quick ");
490 	if (r->ifname[0])
491 		printf("on %s ", r->ifname);
492 	if (r->proto) {
493 		struct protoent *p = getprotobynumber(r->proto);
494 		if (p != NULL)
495 			printf("proto %s ", p->p_name);
496 		else
497 			printf("proto %u ", r->proto);
498 	}
499 	if (!r->src.addr && !r->src.mask && !r->src.port_op && !r->dst.addr && ! r->dst.mask && !r->dst.port_op)
500 		printf("all ");
501 	else {
502 		printf("from ");
503 		if (!r->src.addr && !r->src.mask)
504 			printf("any ");
505 		else {
506 			if (r->src.not)
507 				printf("! ");
508 			print_addr(r->src.addr);
509 			if (r->src.mask != 0xFFFFFFFF) {
510 				printf("/");
511 				print_addr(r->src.mask);
512 			}
513 			printf(" ");
514 		}
515 		if (r->src.port_op)
516 			print_port(r->src.port_op, r->src.port[0],
517 			    r->src.port[1],
518 			    r->proto == IPPROTO_TCP ? "tcp" : "udp");
519 
520 		printf("to ");
521 		if (!r->dst.addr && !r->dst.mask)
522 			printf("any ");
523 		else {
524 			if (r->dst.not)
525 				printf("! ");
526 			print_addr(r->dst.addr);
527 			if (r->dst.mask != 0xFFFFFFFF) {
528 				printf("/");
529 				print_addr(r->dst.mask);
530 			}
531 			printf(" ");
532 		}
533 		if (r->dst.port_op)
534 			print_port(r->dst.port_op, r->dst.port[0],
535 			    r->dst.port[1],
536 			    r->proto == IPPROTO_TCP ? "tcp" : "udp");
537 	}
538 	if (r->flags || r->flagset) {
539 		printf("flags ");
540 		print_flags(r->flags);
541 		printf("/");
542 		print_flags(r->flagset);
543 		printf(" ");
544 	}
545 	if (r->type) {
546 		struct icmptypeent *p;
547 
548 		p = geticmptypebynumber(r->type-1);
549 		if (p != NULL)
550 			printf("icmp-type %s ", p->name);
551 		else
552 			printf("icmp-type %u ", r->type-1);
553 		if (r->code) {
554 			struct icmpcodeent *p;
555 
556 			p = geticmpcodebynumber(r->type-1, r->code-1);
557 			if (p != NULL)
558 				printf("code %s ", p->name);
559 			else
560 				printf("code %u ", r->code-1);
561 		}
562 	}
563 	if (r->keep_state)
564 		printf("keep state ");
565 	if (r->rule_flag & PFRULE_NODF)
566 		printf("no-df ");
567 	if (r->min_ttl)
568 		printf("min-ttl %d ", r->min_ttl);
569 
570 	printf("\n");
571 }
572 
573 int
574 parse_flags(char *s)
575 {
576 	char *p, *q;
577         u_int8_t f = 0;
578 
579         for (p = s; *p; p++) {
580 		if ((q = strchr(tcpflags, *p)) == NULL)
581 			return -1;
582 		else
583 			f |= 1 << (q - tcpflags);
584         }
585         return (f ? f : 63);
586 }
587