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