xref: /openbsd/sbin/pfctl/pfctl_parser.c (revision 082ebc44)
1*082ebc44Swilfried /*	$OpenBSD: pfctl_parser.c,v 1.11 2001/06/26 15:29:05 wilfried Exp $ */
214a9b182Skjell 
314a9b182Skjell /*
414a9b182Skjell  * Copyright (c) 2001, Daniel Hartmeier
514a9b182Skjell  * All rights reserved.
614a9b182Skjell  *
714a9b182Skjell  * Redistribution and use in source and binary forms, with or without
814a9b182Skjell  * modification, are permitted provided that the following conditions
914a9b182Skjell  * are met:
1014a9b182Skjell  *
1114a9b182Skjell  *    - Redistributions of source code must retain the above copyright
1214a9b182Skjell  *      notice, this list of conditions and the following disclaimer.
1314a9b182Skjell  *    - Redistributions in binary form must reproduce the above
1414a9b182Skjell  *      copyright notice, this list of conditions and the following
1514a9b182Skjell  *      disclaimer in the documentation and/or other materials provided
1614a9b182Skjell  *      with the distribution.
1714a9b182Skjell  *
1814a9b182Skjell  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1914a9b182Skjell  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2014a9b182Skjell  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2114a9b182Skjell  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
225974bd37Sdhartmei  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2314a9b182Skjell  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2414a9b182Skjell  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2514a9b182Skjell  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2614a9b182Skjell  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2714a9b182Skjell  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2814a9b182Skjell  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2914a9b182Skjell  * POSSIBILITY OF SUCH DAMAGE.
3014a9b182Skjell  *
3114a9b182Skjell  */
3214a9b182Skjell 
33252d784aSderaadt #include <sys/types.h>
34252d784aSderaadt #include <sys/socket.h>
35252d784aSderaadt #include <net/if.h>
36252d784aSderaadt #include <netinet/in.h>
376329fa59Sderaadt #include <netinet/in_systm.h>
386329fa59Sderaadt #include <netinet/ip.h>
396329fa59Sderaadt #include <netinet/ip_icmp.h>
40252d784aSderaadt #include <net/pfvar.h>
41252d784aSderaadt 
4214a9b182Skjell #include <stdio.h>
4314a9b182Skjell #include <stdlib.h>
4414a9b182Skjell #include <string.h>
4514a9b182Skjell #include <ctype.h>
4614a9b182Skjell #include <netdb.h>
476329fa59Sderaadt #include <stdarg.h>
486329fa59Sderaadt #include <errno.h>
4914a9b182Skjell 
5014a9b182Skjell #include "pfctl_parser.h"
5114a9b182Skjell 
5281a15e5dSderaadt void		 print_addr (u_int32_t);
536d5ce0fbSderaadt void		 print_host (struct pf_state_host *);
546d5ce0fbSderaadt void		 print_seq (struct pf_state_peer *);
5581a15e5dSderaadt void		 print_port (u_int8_t, u_int16_t, u_int16_t, char *);
5681a15e5dSderaadt void		 print_flags (u_int8_t);
5781a15e5dSderaadt char		*next_word (char **);
5881a15e5dSderaadt u_int16_t	 next_number (char **);
5981a15e5dSderaadt u_int32_t	 next_addr (char **);
6081a15e5dSderaadt u_int8_t	 next_flags (char **);
6181a15e5dSderaadt u_int16_t	 rule_port (char *, u_int8_t);
6281a15e5dSderaadt u_int32_t	 rule_mask (u_int8_t);
6314a9b182Skjell 
6481a15e5dSderaadt char *tcpflags = "FSRPAU";
6514a9b182Skjell 
66*082ebc44Swilfried struct icmptypeent {
67*082ebc44Swilfried 	char *name;
68*082ebc44Swilfried 	u_int8_t type;
69*082ebc44Swilfried };
70*082ebc44Swilfried 
71*082ebc44Swilfried struct icmpcodeent {
72*082ebc44Swilfried 	char *name;
73*082ebc44Swilfried 	u_int8_t type;
74*082ebc44Swilfried 	u_int8_t code;
75*082ebc44Swilfried };
76*082ebc44Swilfried 
77*082ebc44Swilfried struct icmptypeent icmp_type[] = {
78*082ebc44Swilfried 	{ "echoreq",	ICMP_ECHO },
79*082ebc44Swilfried 	{ "echorep",	ICMP_ECHOREPLY },
80*082ebc44Swilfried 	{ "unreach",	ICMP_UNREACH },
81*082ebc44Swilfried 	{ "squench",	ICMP_SOURCEQUENCH },
82*082ebc44Swilfried 	{ "redir",	ICMP_REDIRECT },
83*082ebc44Swilfried 	{ "althost",	ICMP_ALTHOSTADDR },
84*082ebc44Swilfried 	{ "routeradv",	ICMP_ROUTERADVERT },
85*082ebc44Swilfried 	{ "routersol",	ICMP_ROUTERSOLICIT },
86*082ebc44Swilfried 	{ "timex",	ICMP_TIMXCEED },
87*082ebc44Swilfried 	{ "paramprob",	ICMP_PARAMPROB },
88*082ebc44Swilfried 	{ "timereq",	ICMP_TSTAMP },
89*082ebc44Swilfried 	{ "timerep",	ICMP_TSTAMPREPLY },
90*082ebc44Swilfried 	{ "inforeq",	ICMP_IREQ },
91*082ebc44Swilfried 	{ "inforep",	ICMP_IREQREPLY },
92*082ebc44Swilfried 	{ "maskreq",	ICMP_MASKREQ },
93*082ebc44Swilfried 	{ "maskrep",	ICMP_MASKREPLY }
94*082ebc44Swilfried };
95*082ebc44Swilfried 
96*082ebc44Swilfried struct icmpcodeent icmp_code[] = {
97*082ebc44Swilfried 	{ "net-unr",		ICMP_UNREACH, 	ICMP_UNREACH_NET },
98*082ebc44Swilfried 	{ "host-unr",		ICMP_UNREACH, 	ICMP_UNREACH_HOST },
99*082ebc44Swilfried 	{ "proto-unr",		ICMP_UNREACH, 	ICMP_UNREACH_PROTOCOL },
100*082ebc44Swilfried 	{ "port-unr",		ICMP_UNREACH, 	ICMP_UNREACH_PORT },
101*082ebc44Swilfried 	{ "needfrag",		ICMP_UNREACH, 	ICMP_UNREACH_NEEDFRAG },
102*082ebc44Swilfried 	{ "srcfail",		ICMP_UNREACH, 	ICMP_UNREACH_SRCFAIL },
103*082ebc44Swilfried 	{ "net-unk",		ICMP_UNREACH, 	ICMP_UNREACH_NET_UNKNOWN },
104*082ebc44Swilfried 	{ "host-unk",		ICMP_UNREACH, 	ICMP_UNREACH_HOST_UNKNOWN },
105*082ebc44Swilfried 	{ "isolate",		ICMP_UNREACH, 	ICMP_UNREACH_ISOLATED },
106*082ebc44Swilfried 	{ "net-prohib",		ICMP_UNREACH, 	ICMP_UNREACH_NET_PROHIB },
107*082ebc44Swilfried 	{ "host-prohib",	ICMP_UNREACH, 	ICMP_UNREACH_HOST_PROHIB },
108*082ebc44Swilfried 	{ "net-tos",		ICMP_UNREACH, 	ICMP_UNREACH_TOSNET },
109*082ebc44Swilfried 	{ "host-tos",		ICMP_UNREACH, 	ICMP_UNREACH_TOSHOST },
110*082ebc44Swilfried 	{ "filter-prohib",	ICMP_UNREACH, 	ICMP_UNREACH_FILTER_PROHIB },
111*082ebc44Swilfried 	{ "host-preced",	ICMP_UNREACH, 	ICMP_UNREACH_HOST_PRECEDENCE },
112*082ebc44Swilfried 	{ "cutoff-preced",	ICMP_UNREACH, 	ICMP_UNREACH_PRECEDENCE_CUTOFF },
113*082ebc44Swilfried 	{ "redir-net",		ICMP_REDIRECT,	ICMP_REDIRECT_NET },
114*082ebc44Swilfried 	{ "redir-host",		ICMP_REDIRECT,	ICMP_REDIRECT_HOST },
115*082ebc44Swilfried 	{ "redir-tos-net",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSNET },
116*082ebc44Swilfried 	{ "redir-tos-host",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSHOST },
117*082ebc44Swilfried 	{ "transit",		ICMP_TIMXCEED,	ICMP_TIMXCEED_INTRANS },
118*082ebc44Swilfried 	{ "reassemb",		ICMP_TIMXCEED,	ICMP_TIMXCEED_REASS },
119*082ebc44Swilfried 	{ "badhead",		ICMP_PARAMPROB,	ICMP_PARAMPROB_ERRATPTR },
120*082ebc44Swilfried 	{ "optmiss",		ICMP_PARAMPROB,	ICMP_PARAMPROB_OPTABSENT },
121*082ebc44Swilfried 	{ "badlen",		ICMP_PARAMPROB,	ICMP_PARAMPROB_LENGTH }
122*082ebc44Swilfried };
123*082ebc44Swilfried 
1246329fa59Sderaadt int
1256329fa59Sderaadt error(int n, char *fmt, ...)
1266329fa59Sderaadt {
1276329fa59Sderaadt 	extern char *__progname;
1286329fa59Sderaadt 	va_list ap;
1296329fa59Sderaadt 
1306329fa59Sderaadt 	va_start(ap, fmt);
1316329fa59Sderaadt 	fprintf(stderr, "%s: line %d ", __progname, n);
1326329fa59Sderaadt 	vfprintf(stderr, fmt, ap);
1336329fa59Sderaadt 	va_end(ap);
1346329fa59Sderaadt 	return (0);
1356329fa59Sderaadt }
1366329fa59Sderaadt 
137*082ebc44Swilfried struct icmptypeent *
138*082ebc44Swilfried geticmptypebynumber(u_int8_t type)
139*082ebc44Swilfried {
140*082ebc44Swilfried 	int i;
141*082ebc44Swilfried 
142*082ebc44Swilfried 	for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) {
143*082ebc44Swilfried 		if(type == icmp_type[i].type)
144*082ebc44Swilfried 			return (&icmp_type[i]);
145*082ebc44Swilfried 	}
146*082ebc44Swilfried 	return (0);
147*082ebc44Swilfried }
148*082ebc44Swilfried 
149*082ebc44Swilfried struct icmptypeent *
150*082ebc44Swilfried geticmptypebyname(char *w)
151*082ebc44Swilfried {
152*082ebc44Swilfried 	int i;
153*082ebc44Swilfried 
154*082ebc44Swilfried 	for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) {
155*082ebc44Swilfried 		if(!strcmp(w, icmp_type[i].name))
156*082ebc44Swilfried 			return (&icmp_type[i]);
157*082ebc44Swilfried 	}
158*082ebc44Swilfried 	return (0);
159*082ebc44Swilfried }
160*082ebc44Swilfried 
161*082ebc44Swilfried struct icmpcodeent *
162*082ebc44Swilfried geticmpcodebynumber(u_int8_t type, u_int8_t code)
163*082ebc44Swilfried {
164*082ebc44Swilfried 	int i;
165*082ebc44Swilfried 
166*082ebc44Swilfried 	for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) {
167*082ebc44Swilfried 		if (type == icmp_code[i].type && code == icmp_code[i].code)
168*082ebc44Swilfried 			return (&icmp_code[i]);
169*082ebc44Swilfried 	}
170*082ebc44Swilfried 	return (0);
171*082ebc44Swilfried }
172*082ebc44Swilfried 
173*082ebc44Swilfried struct icmpcodeent *
174*082ebc44Swilfried geticmpcodebyname(u_long type, char *w)
175*082ebc44Swilfried {
176*082ebc44Swilfried 	int i;
177*082ebc44Swilfried 
178*082ebc44Swilfried 	for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) {
179*082ebc44Swilfried 		if (type == icmp_code[i].type && !strcmp(w, icmp_code[i].name))
180*082ebc44Swilfried 			return (&icmp_code[i]);
181*082ebc44Swilfried 	}
182*082ebc44Swilfried 	return (0);
183*082ebc44Swilfried }
184*082ebc44Swilfried 
18581a15e5dSderaadt void
18614a9b182Skjell print_addr(u_int32_t a)
18714a9b182Skjell {
18814a9b182Skjell 	a = ntohl(a);
18914a9b182Skjell 	printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255);
19014a9b182Skjell }
19114a9b182Skjell 
19281a15e5dSderaadt void
1936d5ce0fbSderaadt print_host(struct pf_state_host *h)
19414a9b182Skjell {
19514a9b182Skjell 	u_int32_t a = ntohl(h->addr);
19614a9b182Skjell 	u_int16_t p = ntohs(h->port);
19781a15e5dSderaadt 
19814a9b182Skjell 	printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, p);
19914a9b182Skjell }
20014a9b182Skjell 
20181a15e5dSderaadt void
2026d5ce0fbSderaadt print_seq(struct pf_state_peer *p)
20314a9b182Skjell {
20414a9b182Skjell 	printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo);
20514a9b182Skjell }
20614a9b182Skjell 
20781a15e5dSderaadt void
20814a9b182Skjell print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
20914a9b182Skjell {
21014a9b182Skjell 	struct servent *s = getservbyport(p1, proto);
21181a15e5dSderaadt 
21214a9b182Skjell 	p1 = ntohs(p1);
21314a9b182Skjell 	p2 = ntohs(p2);
21414a9b182Skjell 	printf("port ");
21514a9b182Skjell 	if (op == 1)
21614a9b182Skjell 		printf("%u >< %u ", p1, p2);
21714a9b182Skjell 	else if (op == 2) {
21814a9b182Skjell 		if (s != NULL)
21914a9b182Skjell 			printf("= %s ", s->s_name);
22014a9b182Skjell 		else
22114a9b182Skjell 			printf("= %u ", p1);
22281a15e5dSderaadt 	} else if (op == 3) {
22314a9b182Skjell 		if (s != NULL)
22414a9b182Skjell 			printf("!= %s ", s->s_name);
22514a9b182Skjell 		else
22614a9b182Skjell 			printf("!= %u ", p1);
22781a15e5dSderaadt 	} else if (op == 4)
22814a9b182Skjell 		printf("< %u ", p1);
22914a9b182Skjell 	else if (op == 5)
23014a9b182Skjell 		printf("<= %u ", p1);
23114a9b182Skjell 	else if (op == 6)
23214a9b182Skjell 		printf("> %u ", p1);
23314a9b182Skjell 	else
23414a9b182Skjell 		printf(">= %u ", p1);
23514a9b182Skjell }
23614a9b182Skjell 
23781a15e5dSderaadt void
23814a9b182Skjell print_flags(u_int8_t f)
23914a9b182Skjell {
24014a9b182Skjell 	int i;
24181a15e5dSderaadt 
24214a9b182Skjell 	for (i = 0; i < 6; ++i)
24314a9b182Skjell 		if (f & (1 << i))
24414a9b182Skjell 			printf("%c", tcpflags[i]);
24514a9b182Skjell }
24614a9b182Skjell 
24714a9b182Skjell void
24881a15e5dSderaadt print_nat(struct pf_nat *n)
24914a9b182Skjell {
25014a9b182Skjell 	printf("nat %s ", n->ifname);
25114a9b182Skjell 	if (n->not)
25214a9b182Skjell 		printf("! ");
25314a9b182Skjell 	print_addr(n->saddr);
25414a9b182Skjell 	if (n->smask != 0xFFFFFFFF) {
25514a9b182Skjell 		printf("/");
25614a9b182Skjell 		print_addr(n->smask);
25714a9b182Skjell 	}
25814a9b182Skjell 	printf(" -> ");
25914a9b182Skjell 	print_addr(n->daddr);
26014a9b182Skjell 	switch (n->proto) {
26114a9b182Skjell 	case IPPROTO_TCP:
26214a9b182Skjell 		printf(" proto tcp");
26314a9b182Skjell 		break;
26414a9b182Skjell 	case IPPROTO_UDP:
26514a9b182Skjell 		printf(" proto udp");
26614a9b182Skjell 		break;
26714a9b182Skjell 	case IPPROTO_ICMP:
26814a9b182Skjell 		printf(" proto icmp");
26914a9b182Skjell 		break;
27014a9b182Skjell 	}
27114a9b182Skjell 	printf("\n");
27214a9b182Skjell }
27314a9b182Skjell 
27414a9b182Skjell void
27581a15e5dSderaadt print_rdr(struct pf_rdr *r)
27614a9b182Skjell {
27714a9b182Skjell 	printf("rdr %s ", r->ifname);
27814a9b182Skjell 	if (r->not)
27914a9b182Skjell 		printf("! ");
28014a9b182Skjell 	print_addr(r->daddr);
28114a9b182Skjell 	if (r->dmask != 0xFFFFFFFF) {
28214a9b182Skjell 		printf("/");
28314a9b182Skjell 		print_addr(r->dmask);
28414a9b182Skjell 	}
28514a9b182Skjell 	printf(" port %u -> ", ntohs(r->dport));
28614a9b182Skjell 	print_addr(r->raddr);
28714a9b182Skjell 	printf(" port %u", ntohs(r->rport));
28814a9b182Skjell 	switch (r->proto) {
28914a9b182Skjell 	case IPPROTO_TCP:
29014a9b182Skjell 		printf(" proto tcp");
29114a9b182Skjell 		break;
29214a9b182Skjell 	case IPPROTO_UDP:
29314a9b182Skjell 		printf(" proto udp");
29414a9b182Skjell 		break;
29514a9b182Skjell 	}
29614a9b182Skjell 	printf("\n");
29714a9b182Skjell }
29814a9b182Skjell 
29914a9b182Skjell void
30081a15e5dSderaadt print_status(struct pf_status *s)
30114a9b182Skjell {
30214a9b182Skjell 	time_t t = time(NULL);
30381a15e5dSderaadt 
30414a9b182Skjell 	printf("%u %u %u", t, s->since, s->running);
30514a9b182Skjell 	if (s->running) {
30614a9b182Skjell 		printf(" %u %u", s->bytes[0], s->bytes[1]);
30714a9b182Skjell 		printf(" %u %u", s->packets[0][0], s->packets[0][1]);
30814a9b182Skjell 		printf(" %u %u", s->packets[1][0], s->packets[1][1]);
30914a9b182Skjell 		printf(" %u %u %u %u", s->states, s->state_inserts,
31014a9b182Skjell 		    s->state_removals, s->state_searches);
31114a9b182Skjell 	}
31214a9b182Skjell 	printf("\n");
31314a9b182Skjell }
31414a9b182Skjell 
31514a9b182Skjell void
31681a15e5dSderaadt print_state(struct pf_state *s)
31714a9b182Skjell {
3186d5ce0fbSderaadt 	struct pf_state_peer *src, *dst;
31914a9b182Skjell 	u_int8_t hrs, min, sec;
320252d784aSderaadt 
32114a9b182Skjell 	if (s->direction == PF_OUT) {
32214a9b182Skjell 		src = &s->src;
32314a9b182Skjell 		dst = &s->dst;
32414a9b182Skjell 	} else {
32514a9b182Skjell 		src = &s->dst;
32614a9b182Skjell 		dst = &s->src;
32714a9b182Skjell 	}
32814a9b182Skjell 	switch (s->proto) {
32914a9b182Skjell 	case IPPROTO_TCP:
33014a9b182Skjell 		printf("TCP  ");
33114a9b182Skjell 		break;
33214a9b182Skjell 	case IPPROTO_UDP:
33314a9b182Skjell 		printf("UDP  ");
33414a9b182Skjell 		break;
33514a9b182Skjell 	case IPPROTO_ICMP:
33614a9b182Skjell 		printf("ICMP ");
33714a9b182Skjell 		break;
33814a9b182Skjell 	default:
33914a9b182Skjell 		printf("???? ");
34014a9b182Skjell 		break;
34114a9b182Skjell 	}
34214a9b182Skjell 	if ((s->lan.addr != s->gwy.addr) || (s->lan.port != s->gwy.port)) {
34314a9b182Skjell 		print_host(&s->lan);
34414a9b182Skjell 		if (s->direction == PF_OUT)
34514a9b182Skjell 			printf(" -> ");
34614a9b182Skjell 		else
34714a9b182Skjell 			printf(" <- ");
34814a9b182Skjell 	}
34914a9b182Skjell 	print_host(&s->gwy);
35014a9b182Skjell 	if (s->direction == PF_OUT)
35114a9b182Skjell 		printf(" -> ");
35214a9b182Skjell 	else
35314a9b182Skjell 		printf(" <- ");
35414a9b182Skjell 	print_host(&s->ext);
35514a9b182Skjell 	printf("\n");
35614a9b182Skjell 
35714a9b182Skjell 	printf("%u:%u  ", src->state, dst->state);
35814a9b182Skjell 	if (s->proto == IPPROTO_TCP) {
35914a9b182Skjell 		print_seq(src);
36014a9b182Skjell 		printf("    ");
36114a9b182Skjell 		print_seq(dst);
36214a9b182Skjell 		printf("\n     ");
36314a9b182Skjell 	}
36414a9b182Skjell 
36514a9b182Skjell 	sec = s->creation % 60;
36614a9b182Skjell 	s->creation /= 60;
36714a9b182Skjell 	min = s->creation % 60;
36814a9b182Skjell 	s->creation /= 60;
36914a9b182Skjell 	hrs = s->creation;
37014a9b182Skjell 	printf("age %.2u:%.2u:%.2u", hrs, min, sec);
37114a9b182Skjell 	sec = s->expire % 60;
37214a9b182Skjell 	s->expire /= 60;
37314a9b182Skjell 	min = s->expire % 60;
37414a9b182Skjell 	s->expire /= 60;
37514a9b182Skjell 	hrs = s->expire;
37614a9b182Skjell 	printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec);
37714a9b182Skjell 	printf(", %u pkts, %u bytes\n", s->packets, s->bytes);
37814a9b182Skjell 	printf("\n");
37914a9b182Skjell }
38014a9b182Skjell 
38114a9b182Skjell void
38281a15e5dSderaadt print_rule(struct pf_rule *r)
38314a9b182Skjell {
38414a9b182Skjell 	if (r->action == 0)
38514a9b182Skjell 		printf("pass ");
38614a9b182Skjell 	else
38714a9b182Skjell 		printf("block ");
38814a9b182Skjell 	if (r->action == 2)
38914a9b182Skjell 		printf("return-rst ");
39014a9b182Skjell 	if (r->direction == 0)
39114a9b182Skjell 		printf("in ");
39214a9b182Skjell 	else
39314a9b182Skjell 		printf("out ");
39414a9b182Skjell 	if (r->log)
39514a9b182Skjell 		printf("log ");
39614a9b182Skjell 	if (r->quick)
39714a9b182Skjell 		printf("quick ");
39814a9b182Skjell 	if (r->ifname[0])
39914a9b182Skjell 		printf("on %s ", r->ifname);
40014a9b182Skjell 	if (r->proto) {
40114a9b182Skjell 		struct protoent *p = getprotobynumber(r->proto);
40214a9b182Skjell 		if (p != NULL)
40314a9b182Skjell 			printf("proto %s ", p->p_name);
40414a9b182Skjell 		else
40514a9b182Skjell 			printf("proto %u ", r->proto);
40614a9b182Skjell 	}
407ade2013bSwilfried 	if (!r->src.addr && !r->src.mask && !r->src.port_op && !r->dst.addr && ! r->dst.mask && !r->dst.port_op)
40814a9b182Skjell 		printf("all ");
40914a9b182Skjell 	else {
41014a9b182Skjell 		printf("from ");
411ade2013bSwilfried 		if (!r->src.addr && !r->src.mask)
41214a9b182Skjell 			printf("any ");
41314a9b182Skjell 		else {
41414a9b182Skjell 			if (r->src.not)
41514a9b182Skjell 				printf("! ");
41614a9b182Skjell 			print_addr(r->src.addr);
41714a9b182Skjell 			if (r->src.mask != 0xFFFFFFFF) {
41814a9b182Skjell 				printf("/");
41914a9b182Skjell 				print_addr(r->src.mask);
42014a9b182Skjell 			}
42114a9b182Skjell 			printf(" ");
42214a9b182Skjell 		}
42314a9b182Skjell 		if (r->src.port_op)
42414a9b182Skjell 			print_port(r->src.port_op, r->src.port[0],
4255df8e51cSsmart 			    r->src.port[1],
4265df8e51cSsmart 			    r->proto == IPPROTO_TCP ? "tcp" : "udp");
42714a9b182Skjell 
42814a9b182Skjell 		printf("to ");
429ade2013bSwilfried 		if (!r->dst.addr && !r->dst.mask)
43014a9b182Skjell 			printf("any ");
43114a9b182Skjell 		else {
43214a9b182Skjell 			if (r->dst.not)
43314a9b182Skjell 				printf("! ");
43414a9b182Skjell 			print_addr(r->dst.addr);
43514a9b182Skjell 			if (r->dst.mask != 0xFFFFFFFF) {
43614a9b182Skjell 				printf("/");
43714a9b182Skjell 				print_addr(r->dst.mask);
43814a9b182Skjell 			}
43914a9b182Skjell 			printf(" ");
44014a9b182Skjell 		}
44114a9b182Skjell 		if (r->dst.port_op)
44214a9b182Skjell 			print_port(r->dst.port_op, r->dst.port[0],
4435df8e51cSsmart 			    r->dst.port[1],
4445df8e51cSsmart 			    r->proto == IPPROTO_TCP ? "tcp" : "udp");
44514a9b182Skjell 	}
44614a9b182Skjell 	if (r->flags || r->flagset) {
44714a9b182Skjell 		printf("flags ");
44814a9b182Skjell 		print_flags(r->flags);
44914a9b182Skjell 		printf("/");
45014a9b182Skjell 		print_flags(r->flagset);
45114a9b182Skjell 		printf(" ");
45214a9b182Skjell 	}
453*082ebc44Swilfried 	if (r->type) {
454*082ebc44Swilfried 		struct icmptypeent *p;
455*082ebc44Swilfried 
456*082ebc44Swilfried 		p = geticmptypebynumber(r->type-1);
457*082ebc44Swilfried 		if (p != NULL)
458*082ebc44Swilfried 			printf("icmp-type %s ", p->name);
459*082ebc44Swilfried 		else
46014a9b182Skjell 			printf("icmp-type %u ", r->type-1);
461*082ebc44Swilfried 		if (r->code) {
462*082ebc44Swilfried 			struct icmpcodeent *p;
463*082ebc44Swilfried 
464*082ebc44Swilfried 			p = geticmpcodebynumber(r->type-1, r->code-1);
465*082ebc44Swilfried 			if (p != NULL)
466*082ebc44Swilfried 				printf("code %s ", p->name);
467*082ebc44Swilfried 			else
46814a9b182Skjell 				printf("code %u ", r->code-1);
469*082ebc44Swilfried 		}
470*082ebc44Swilfried 	}
47114a9b182Skjell 	if (r->keep_state)
47214a9b182Skjell 		printf("keep state ");
47314a9b182Skjell 	printf("\n");
47414a9b182Skjell }
47514a9b182Skjell 
47614a9b182Skjell char *
47714a9b182Skjell next_line(char **s)
47814a9b182Skjell {
47981a15e5dSderaadt 	char *l = *s;
48081a15e5dSderaadt 
48114a9b182Skjell 	while (**s && (**s != '\n'))
48214a9b182Skjell 		(*s)++;
48314a9b182Skjell 	if (**s) {
48414a9b182Skjell 		**s = 0;
48514a9b182Skjell 		(*s)++;
48614a9b182Skjell 	}
487dbfb98deSprovos 	return (l);
48814a9b182Skjell }
48914a9b182Skjell 
49081a15e5dSderaadt char *
49114a9b182Skjell next_word(char **s)
49214a9b182Skjell {
49314a9b182Skjell 	char *w;
49481a15e5dSderaadt 
49514a9b182Skjell 	while ((**s == ' ') || (**s == '\t') || (**s == '\n'))
49614a9b182Skjell 		(*s)++;
49714a9b182Skjell 	w = *s;
49814a9b182Skjell 	while (**s && (**s != ' ') && (**s != '\t') && (**s != '\n'))
49914a9b182Skjell 		(*s)++;
50014a9b182Skjell 	if (**s) {
50114a9b182Skjell 		**s = 0;
50214a9b182Skjell 		(*s)++;
50314a9b182Skjell 	}
504dbfb98deSprovos 	return (w);
50514a9b182Skjell }
50614a9b182Skjell 
50781a15e5dSderaadt u_int16_t
50814a9b182Skjell next_number(char **s)
50914a9b182Skjell {
51014a9b182Skjell 	u_int16_t n = 0;
51181a15e5dSderaadt 
51214a9b182Skjell 	while (**s && !isdigit(**s))
51314a9b182Skjell 		(*s)++;
51414a9b182Skjell 	while (**s && isdigit(**s)) {
51514a9b182Skjell 		n *= 10;
51614a9b182Skjell 		n += **s - '0';
51714a9b182Skjell 		(*s)++;
51814a9b182Skjell 	}
519dbfb98deSprovos 	return (n);
52014a9b182Skjell }
52114a9b182Skjell 
52281a15e5dSderaadt u_int32_t
52314a9b182Skjell next_addr(char **w)
52414a9b182Skjell {
52514a9b182Skjell 	u_int8_t a, b, c, d;
52614a9b182Skjell 	a = next_number(w);
52714a9b182Skjell 	b = next_number(w);
52814a9b182Skjell 	c = next_number(w);
52914a9b182Skjell 	d = next_number(w);
530dbfb98deSprovos 	return (htonl((a << 24) | (b << 16) | (c << 8) | d));
53114a9b182Skjell }
53214a9b182Skjell 
53381a15e5dSderaadt u_int8_t
53414a9b182Skjell next_flags(char **s)
53514a9b182Skjell {
53614a9b182Skjell 	u_int8_t f = 0;
53714a9b182Skjell 	char *p;
53881a15e5dSderaadt 
53914a9b182Skjell 	while (**s && !strchr(tcpflags, **s))
54014a9b182Skjell 		(*s)++;
54114a9b182Skjell 	while (**s && ((p = strchr(tcpflags, **s)) != NULL)) {
54214a9b182Skjell 		f |= 1 << (p-tcpflags);
54314a9b182Skjell 		(*s)++;
54414a9b182Skjell 	}
545dbfb98deSprovos 	return (f ? f : 63);
54614a9b182Skjell }
54714a9b182Skjell 
54881a15e5dSderaadt u_int16_t
54914a9b182Skjell rule_port(char *w, u_int8_t p)
55014a9b182Skjell {
55114a9b182Skjell 	struct servent *s;
5526329fa59Sderaadt 	u_long ul;
5536329fa59Sderaadt 	char *ep;
55481a15e5dSderaadt 
5556329fa59Sderaadt 	errno = 0;
5566329fa59Sderaadt 	ul = strtoul(w, &ep, 10);
5576329fa59Sderaadt 	if (*w == '\0' || *ep != '\0') {
5585df8e51cSsmart 		s = getservbyname(w, p == IPPROTO_TCP ? "tcp" : "udp");
55914a9b182Skjell 		if (s == NULL)
560dbfb98deSprovos 			return (0);
561dbfb98deSprovos 		return (s->s_port);
56214a9b182Skjell 	}
5636329fa59Sderaadt 	if (errno == ERANGE && ul == ULONG_MAX)
5646329fa59Sderaadt 		return (0);
5656329fa59Sderaadt 	if (ul > USHRT_MAX) {
5666329fa59Sderaadt 		errno = ERANGE;
5676329fa59Sderaadt 		return (0);
5686329fa59Sderaadt 	}
5696329fa59Sderaadt 	return (htons(ul));
5706329fa59Sderaadt }
57114a9b182Skjell 
57281a15e5dSderaadt u_int32_t
57314a9b182Skjell rule_mask(u_int8_t b)
57414a9b182Skjell {
57514a9b182Skjell 	u_int32_t m = 0;
57614a9b182Skjell 	int i;
57781a15e5dSderaadt 
57814a9b182Skjell 	for (i = 31; i > 31-b; --i)
57914a9b182Skjell 		m |= (1 << i);
580dbfb98deSprovos 	return (htonl(m));
58114a9b182Skjell }
58214a9b182Skjell 
58314a9b182Skjell int
58481a15e5dSderaadt parse_rule(int n, char *l, struct pf_rule *r)
58514a9b182Skjell {
58614a9b182Skjell 	char *w;
58781a15e5dSderaadt 	memset(r, 0, sizeof(struct pf_rule));
58814a9b182Skjell 	w = next_word(&l);
58914a9b182Skjell 
59014a9b182Skjell 	/* pass / block */
59114a9b182Skjell 	if (!strcmp(w, "pass" ))
59214a9b182Skjell 		r->action = 0;
59314a9b182Skjell 	else if (!strcmp(w, "block"))
59414a9b182Skjell 		r->action = 1;
59514a9b182Skjell 	else {
5966329fa59Sderaadt 		error(n, "expected pass/block, got %s\n", w);
597dbfb98deSprovos 		return (0);
59814a9b182Skjell 	}
59914a9b182Skjell 	w = next_word(&l);
60014a9b182Skjell 
60114a9b182Skjell 	/* return-rst */
60214a9b182Skjell 	if ((r->action == 1) && !strcmp(w, "return-rst")) {
60314a9b182Skjell 		r->action = 2;
60414a9b182Skjell 		w = next_word(&l);
60514a9b182Skjell 	}
60614a9b182Skjell 
60714a9b182Skjell 	/* in / out */
60814a9b182Skjell 	if (!strcmp(w, "in" ))
60914a9b182Skjell 		r->direction = 0;
61014a9b182Skjell 	else if (!strcmp(w, "out"))
61114a9b182Skjell 		r->direction = 1;
61214a9b182Skjell 	else {
6136329fa59Sderaadt 		error(n, "expected in/out, got %s\n", w);
614dbfb98deSprovos 		return (0);
61514a9b182Skjell 	}
61614a9b182Skjell 	w = next_word(&l);
61714a9b182Skjell 
61814a9b182Skjell 	/* log */
61914a9b182Skjell 	if (!strcmp(w, "log")) {
62014a9b182Skjell 		r->log = 1;
62114a9b182Skjell 		w = next_word(&l);
62214a9b182Skjell 	}
62314a9b182Skjell 
62414a9b182Skjell 	/* quick */
62514a9b182Skjell 	if (!strcmp(w, "quick")) {
62614a9b182Skjell 		r->quick = 1;
62714a9b182Skjell 		w = next_word(&l);
62814a9b182Skjell 	}
62914a9b182Skjell 
63014a9b182Skjell 	/* on <if> */
63114a9b182Skjell 	if (!strcmp(w, "on")) {
63214a9b182Skjell 		w = next_word(&l);
63314a9b182Skjell 		strncpy(r->ifname, w, 16);
63414a9b182Skjell 		w = next_word(&l);
63514a9b182Skjell 	}
63614a9b182Skjell 
63714a9b182Skjell 	/* proto tcp/udp/icmp */
63814a9b182Skjell 	if (!strcmp(w, "proto")) {
63914a9b182Skjell 		struct protoent *p;
64014a9b182Skjell 		w = next_word(&l);
64114a9b182Skjell 		p = getprotobyname(w);
64214a9b182Skjell 		if (p == NULL) {
6436329fa59Sderaadt 			error(n, "unknown protocol %s\n", w);
644dbfb98deSprovos 			return (0);
64514a9b182Skjell 		}
64614a9b182Skjell 		r->proto = p->p_proto;
64714a9b182Skjell 		w = next_word(&l);
64814a9b182Skjell 	}
64914a9b182Skjell 
65014a9b182Skjell 	/* all / from src to dst */
65114a9b182Skjell 	if (!strcmp(w, "all" ))
65214a9b182Skjell 		w = next_word(&l);
65314a9b182Skjell 	else if (!strcmp(w, "from")) {
65414a9b182Skjell 		w = next_word(&l);
65514a9b182Skjell 
65614a9b182Skjell 		/* source address */
65714a9b182Skjell 		if (!strcmp(w, "any"))
65814a9b182Skjell 			w = next_word(&l);
65914a9b182Skjell 		else {
66014a9b182Skjell 			if (!strcmp(w, "!")) {
66114a9b182Skjell 				r->src.not = 1;
66214a9b182Skjell 				w = next_word(&l);
66314a9b182Skjell 			}
66414a9b182Skjell 			r->src.addr = next_addr(&w);
66514a9b182Skjell 			if (!*w)
66614a9b182Skjell 				r->src.mask = 0xFFFFFFFF;
66714a9b182Skjell 			else if (*w == '/')
66814a9b182Skjell 				r->src.mask = rule_mask(next_number(&w));
66914a9b182Skjell 			else {
6706329fa59Sderaadt 				error(n, "expected /, got '%c'\n", *w);
671dbfb98deSprovos 				return (0);
67214a9b182Skjell 			}
67314a9b182Skjell 			w = next_word(&l);
67414a9b182Skjell 		}
67514a9b182Skjell 
67614a9b182Skjell 		/* source port */
6775df8e51cSsmart 		if (((r->proto == IPPROTO_TCP) || (r->proto == IPPROTO_UDP)) &&
6785df8e51cSsmart 		    !strcmp(w, "port")) {
67914a9b182Skjell 			w = next_word(&l);
68014a9b182Skjell 			if (!strcmp(w, "=" ))
68114a9b182Skjell 				r->src.port_op = 2;
68214a9b182Skjell 			else if (!strcmp(w, "!="))
68314a9b182Skjell 				r->src.port_op = 3;
68414a9b182Skjell 			else if (!strcmp(w, "<" ))
68514a9b182Skjell 				r->src.port_op = 4;
68614a9b182Skjell 			else if (!strcmp(w, "<="))
68714a9b182Skjell 				r->src.port_op = 5;
68814a9b182Skjell 			else if (!strcmp(w, ">" ))
68914a9b182Skjell 				r->src.port_op = 6;
69014a9b182Skjell 			else if (!strcmp(w, ">="))
69114a9b182Skjell 				r->src.port_op = 7;
69214a9b182Skjell 			else
69314a9b182Skjell 				r->src.port_op = 1;
69414a9b182Skjell 			if (r->src.port_op != 1)
69514a9b182Skjell 				w = next_word(&l);
69614a9b182Skjell 			r->src.port[0] = rule_port(w, r->proto);
69714a9b182Skjell 			w = next_word(&l);
69814a9b182Skjell 			if (r->src.port_op == 1) {
69914a9b182Skjell 				if (strcmp(w, "<>") && strcmp(w, "><")) {
7006329fa59Sderaadt 					error(n, "expected <>/><, got %s\n",
7016329fa59Sderaadt 					    w);
702dbfb98deSprovos 					return (0);
70314a9b182Skjell 				}
70414a9b182Skjell 				w = next_word(&l);
70514a9b182Skjell 				r->src.port[1] = rule_port(w, r->proto);
70614a9b182Skjell 				w = next_word(&l);
70714a9b182Skjell 			}
70814a9b182Skjell 		}
70914a9b182Skjell 
71014a9b182Skjell 		/* destination address */
71114a9b182Skjell 		if (strcmp(w, "to")) {
7126329fa59Sderaadt 			error(n, "expected to, got %s\n", w);
713dbfb98deSprovos 			return (0);
71414a9b182Skjell 		}
71514a9b182Skjell 		w = next_word(&l);
71614a9b182Skjell 		if (!strcmp(w, "any"))
71714a9b182Skjell 			w = next_word(&l);
71814a9b182Skjell 		else {
71914a9b182Skjell 			if (!strcmp(w, "!")) {
72014a9b182Skjell 				r->dst.not = 1;
72114a9b182Skjell 				w = next_word(&l);
72214a9b182Skjell 			}
72314a9b182Skjell 			r->dst.addr = next_addr(&w);
72414a9b182Skjell 			if (!*w)
72514a9b182Skjell 				r->dst.mask = 0xFFFFFFFF;
72614a9b182Skjell 			else if (*w == '/')
72714a9b182Skjell 				r->dst.mask = rule_mask(next_number(&w));
72814a9b182Skjell 			else {
7296329fa59Sderaadt 				error(n, "expected /, got '%c'\n", *w);
730dbfb98deSprovos 				return (0);
73114a9b182Skjell 			}
73214a9b182Skjell 			w = next_word(&l);
73314a9b182Skjell 		}
73414a9b182Skjell 
73514a9b182Skjell 		/* destination port */
7365df8e51cSsmart 		if (((r->proto == IPPROTO_TCP) || (r->proto == IPPROTO_UDP)) &&
7375df8e51cSsmart 		    !strcmp(w, "port")) {
73814a9b182Skjell 			w = next_word(&l);
73914a9b182Skjell 			if (!strcmp(w, "=" ))
74014a9b182Skjell 				r->dst.port_op = 2;
74114a9b182Skjell 			else if (!strcmp(w, "!="))
74214a9b182Skjell 				r->dst.port_op = 3;
74314a9b182Skjell 			else if (!strcmp(w, "<" ))
74414a9b182Skjell 				r->dst.port_op = 4;
74514a9b182Skjell 			else if (!strcmp(w, "<="))
74614a9b182Skjell 				r->dst.port_op = 5;
74714a9b182Skjell 			else if (!strcmp(w, ">" ))
74814a9b182Skjell 				r->dst.port_op = 6;
74914a9b182Skjell 			else if (!strcmp(w, ">="))
75014a9b182Skjell 				r->dst.port_op = 7;
75114a9b182Skjell 			else
75214a9b182Skjell 				r->dst.port_op = 1;
75314a9b182Skjell 			if (r->dst.port_op != 1)
75414a9b182Skjell 				w = next_word(&l);
75514a9b182Skjell 			r->dst.port[0] = rule_port(w, r->proto);
75614a9b182Skjell 			w = next_word(&l);
75714a9b182Skjell 			if (r->dst.port_op == 1) {
75814a9b182Skjell 				if (strcmp(w, "<>") && strcmp(w, "><")) {
7596329fa59Sderaadt 					error(n, "expected <>/><, got %s\n",
7606329fa59Sderaadt 					    w);
761dbfb98deSprovos 					return (0);
76214a9b182Skjell 				}
76314a9b182Skjell 				w = next_word(&l);
76414a9b182Skjell 				r->dst.port[1] = rule_port(w, r->proto);
76514a9b182Skjell 				w = next_word(&l);
76614a9b182Skjell 			}
76714a9b182Skjell 		}
76814a9b182Skjell 
7696329fa59Sderaadt 	} else {
7706329fa59Sderaadt 		error(n, "expected all/from, got %s\n", w);
771dbfb98deSprovos 		return (0);
77214a9b182Skjell 	}
77314a9b182Skjell 
77414a9b182Skjell 	/* flags */
77514a9b182Skjell 	if (!strcmp(w, "flags")) {
7765df8e51cSsmart 		if (r->proto != IPPROTO_TCP) {
7776329fa59Sderaadt 			error(n, "flags only valid for proto tcp\n");
778dbfb98deSprovos 			return (0);
7796329fa59Sderaadt 		} else {
78014a9b182Skjell 			w = next_word(&l);
78114a9b182Skjell 			r->flags = next_flags(&w);
78214a9b182Skjell 			r->flagset = next_flags(&w);
78314a9b182Skjell 			w = next_word(&l);
78414a9b182Skjell 		}
78514a9b182Skjell 	}
78614a9b182Skjell 
78714a9b182Skjell 	/* icmp type/code */
78814a9b182Skjell 	if (!strcmp(w, "icmp-type")) {
7895df8e51cSsmart 		if (r->proto != IPPROTO_ICMP) {
7906329fa59Sderaadt 			error(n, "icmp-type only valid for proto icmp\n");
7916329fa59Sderaadt 			return (0);
7926329fa59Sderaadt 		} else {
7936329fa59Sderaadt 			u_long ul;
7946329fa59Sderaadt 			char *ep;
7956329fa59Sderaadt 
7966329fa59Sderaadt 			w = next_word(&l);
7976329fa59Sderaadt 
7986329fa59Sderaadt 			errno = 0;
7996329fa59Sderaadt 			ul = strtoul(w, &ep, 10);
800*082ebc44Swilfried 			if (w[0] == '\0' || *ep != '\0') {
801*082ebc44Swilfried 				struct icmptypeent *p;
802*082ebc44Swilfried 
803*082ebc44Swilfried 				p = geticmptypebyname(w);
804*082ebc44Swilfried 				if (p == NULL) {
805*082ebc44Swilfried 					error(n, "unknown icmp-type %s\n", w);
806*082ebc44Swilfried 					return (0);
807*082ebc44Swilfried 				}
808*082ebc44Swilfried 				ul = p->type;
809*082ebc44Swilfried 			} else if ((errno == ERANGE && ul == ULONG_MAX) ||
8106329fa59Sderaadt 			    ul > ICMP_MAXTYPE) {
8116329fa59Sderaadt 				error(n, "icmp-type type wrong\n");
812dbfb98deSprovos 				return (0);
81314a9b182Skjell 			}
8146329fa59Sderaadt 			r->type = ul+1;
8156329fa59Sderaadt 
81614a9b182Skjell 			w = next_word(&l);
81714a9b182Skjell 			if (!strcmp(w, "code")) {
81814a9b182Skjell 				w = next_word(&l);
8196329fa59Sderaadt 
8206329fa59Sderaadt 				errno = 0;
8216329fa59Sderaadt 				ul = strtoul(w, &ep, 10);
822*082ebc44Swilfried 				if (w[0] == '\0' || *ep != '\0') {
823*082ebc44Swilfried 					struct icmpcodeent *p;
824*082ebc44Swilfried 
825*082ebc44Swilfried 					p = geticmpcodebyname(r->type-1, w);
826*082ebc44Swilfried 					if (p == NULL) {
827*082ebc44Swilfried 						error(n, "unknown code %s\n", w);
828*082ebc44Swilfried 						return (0);
829*082ebc44Swilfried 					}
830*082ebc44Swilfried 					ul = p->code;
831*082ebc44Swilfried 				} else if ((errno == ERANGE && ul == ULONG_MAX) ||
8326329fa59Sderaadt 				    ul > 255) {
8336329fa59Sderaadt 					error(n, "icmp-type code wrong\n");
8346329fa59Sderaadt 					return (0);
8356329fa59Sderaadt 				}
8366329fa59Sderaadt 				r->code = ul + 1;
837*082ebc44Swilfried 
83814a9b182Skjell 				w = next_word(&l);
83914a9b182Skjell 			}
84014a9b182Skjell 		}
84114a9b182Skjell 	}
84214a9b182Skjell 
84314a9b182Skjell 	/* keep */
84414a9b182Skjell 	if (!strcmp(w, "keep")) {
84514a9b182Skjell 		w = next_word(&l);
84614a9b182Skjell 		if (!strcmp(w, "state")) {
84714a9b182Skjell 			w = next_word(&l);
84814a9b182Skjell 			r->keep_state = 1;
8496329fa59Sderaadt 		} else {
8506329fa59Sderaadt 			error(n, "expected state, got %s\n", w);
851dbfb98deSprovos 			return (0);
85214a9b182Skjell 		}
85314a9b182Skjell 	}
85414a9b182Skjell 
85514a9b182Skjell 	/* no further options expected */
85614a9b182Skjell 	while (*w) {
8576329fa59Sderaadt 		error(n, "unexpected %s\n", w);
85814a9b182Skjell 		w = next_word(&l);
85914a9b182Skjell 	}
86014a9b182Skjell 
861dbfb98deSprovos 	return (1);
86214a9b182Skjell }
86314a9b182Skjell 
86414a9b182Skjell int
86581a15e5dSderaadt parse_nat(int n, char *l, struct pf_nat *nat)
86614a9b182Skjell {
86714a9b182Skjell 	char *w;
86881a15e5dSderaadt 
86981a15e5dSderaadt 	memset(nat, 0, sizeof(struct pf_nat));
87014a9b182Skjell 	w = next_word(&l);
87114a9b182Skjell 
87214a9b182Skjell 	/* nat */
87314a9b182Skjell 	if (strcmp(w, "nat" )) {
8746329fa59Sderaadt 		error(n, "expected nat, got %s\n", w);
875dbfb98deSprovos 		return (0);
87614a9b182Skjell 	}
87714a9b182Skjell 	w = next_word(&l);
87814a9b182Skjell 
87914a9b182Skjell 	/* if */
88014a9b182Skjell 	strncpy(nat->ifname, w, 16);
88114a9b182Skjell 	w = next_word(&l);
88214a9b182Skjell 
88314a9b182Skjell 	/* internal addr/mask */
88414a9b182Skjell 	if (!strcmp(w, "!")) {
88514a9b182Skjell 		nat->not = 1;
88614a9b182Skjell 		w = next_word(&l);
88714a9b182Skjell 	}
88814a9b182Skjell 	nat->saddr = next_addr(&w);
88914a9b182Skjell 	if (!*w)
89014a9b182Skjell 		nat->smask = 0xFFFFFFFF;
89114a9b182Skjell 	else if (*w == '/')
89214a9b182Skjell 		nat->smask = rule_mask(next_number(&w));
89314a9b182Skjell 	else {
8946329fa59Sderaadt 		error(n, "expected /, got '%c'\n", *w);
895dbfb98deSprovos 		return (0);
89614a9b182Skjell 	}
89714a9b182Skjell 	w = next_word(&l);
89814a9b182Skjell 
89914a9b182Skjell 	/* -> */
90014a9b182Skjell 	if (strcmp(w, "->")) {
9016329fa59Sderaadt 		error(n, "expected ->, got %s\n", w);
902dbfb98deSprovos 		return (0);
90314a9b182Skjell 	}
90414a9b182Skjell 	w = next_word(&l);
90514a9b182Skjell 
90614a9b182Skjell 	/* external addr */
90714a9b182Skjell 	nat->daddr = next_addr(&w);
90814a9b182Skjell 	w = next_word(&l);
90914a9b182Skjell 
91014a9b182Skjell 	/* proto */
91114a9b182Skjell 	if (!strcmp(w, "proto")) {
91214a9b182Skjell 		w = next_word(&l);
91314a9b182Skjell 		if (!strcmp(w, "tcp"))
91414a9b182Skjell 			nat->proto = IPPROTO_TCP;
91514a9b182Skjell 		else if (!strcmp(w, "udp"))
91614a9b182Skjell 			nat->proto = IPPROTO_UDP;
91714a9b182Skjell 		else if (!strcmp(w, "icmp"))
91814a9b182Skjell 			nat->proto = IPPROTO_ICMP;
91914a9b182Skjell 		else {
9206329fa59Sderaadt 			error(n, "expected tcp/udp/icmp, got %s\n", w);
921dbfb98deSprovos 			return (0);
92214a9b182Skjell 		}
92314a9b182Skjell 		w = next_word(&l);
92414a9b182Skjell 	}
92514a9b182Skjell 
92614a9b182Skjell 	/* no further options expected */
92714a9b182Skjell 	while (*w) {
9286329fa59Sderaadt 		error(n, "unexpected %s\n", w);
92914a9b182Skjell 		w = next_word(&l);
93014a9b182Skjell 	}
93114a9b182Skjell 
932dbfb98deSprovos 	return (1);
93314a9b182Skjell }
93414a9b182Skjell 
93514a9b182Skjell int
93681a15e5dSderaadt parse_rdr(int n, char *l, struct pf_rdr *rdr)
93714a9b182Skjell {
93814a9b182Skjell 	char *w;
93981a15e5dSderaadt 
94081a15e5dSderaadt 	memset(rdr, 0, sizeof(struct pf_rdr));
94114a9b182Skjell 	w = next_word(&l);
94214a9b182Skjell 
94314a9b182Skjell 	/* rdr */
94414a9b182Skjell 	if (strcmp(w, "rdr" )) {
9456329fa59Sderaadt 		error(n, "expected rdr, got %s\n", w);
946dbfb98deSprovos 		return (0);
94714a9b182Skjell 	}
94814a9b182Skjell 	w = next_word(&l);
94914a9b182Skjell 
95014a9b182Skjell 	/* if */
95114a9b182Skjell 	strncpy(rdr->ifname, w, 16);
95214a9b182Skjell 	w = next_word(&l);
95314a9b182Skjell 
95414a9b182Skjell 	/* external addr/mask */
95514a9b182Skjell 	if (!strcmp(w, "!")) {
95614a9b182Skjell 		rdr->not = 1;
95714a9b182Skjell 		w = next_word(&l);
95814a9b182Skjell 	}
95914a9b182Skjell 	rdr->daddr = next_addr(&w);
96014a9b182Skjell 	if (!*w)
96114a9b182Skjell 		rdr->dmask = 0xFFFFFFFF;
96214a9b182Skjell 	else if (*w == '/')
96314a9b182Skjell 		rdr->dmask = rule_mask(next_number(&w));
96414a9b182Skjell 	else {
9656329fa59Sderaadt 		error(n, "expected /, got '%c'\n", *w);
966dbfb98deSprovos 		return (0);
96714a9b182Skjell 	}
96814a9b182Skjell 	w = next_word(&l);
96914a9b182Skjell 
97014a9b182Skjell 	/* external port */
97114a9b182Skjell 	if (strcmp(w, "port")) {
9726329fa59Sderaadt 		error(n, "expected port, got %s\n", w);
973dbfb98deSprovos 		return (0);
97414a9b182Skjell 	}
97514a9b182Skjell 	w = next_word(&l);
97614a9b182Skjell 	rdr->dport = htons(next_number(&w));
97714a9b182Skjell 	w = next_word(&l);
97814a9b182Skjell 
97914a9b182Skjell 	/* -> */
98014a9b182Skjell 	if (strcmp(w, "->")) {
9816329fa59Sderaadt 		error(n, "expected ->, got %s\n", w);
982dbfb98deSprovos 		return (0);
98314a9b182Skjell 	}
98414a9b182Skjell 	w = next_word(&l);
98514a9b182Skjell 
98614a9b182Skjell 	/* internal addr */
98714a9b182Skjell 	rdr->raddr = next_addr(&w);
98814a9b182Skjell 	w = next_word(&l);
98914a9b182Skjell 
99014a9b182Skjell 	/* internal port */
99114a9b182Skjell 	if (strcmp(w, "port")) {
9926329fa59Sderaadt 		error(n, "expected port, got %s\n", w);
993dbfb98deSprovos 		return (0);
99414a9b182Skjell 	}
99514a9b182Skjell 	w = next_word(&l);
99614a9b182Skjell 	rdr->rport = htons(next_number(&w));
99714a9b182Skjell 	w = next_word(&l);
99814a9b182Skjell 
99914a9b182Skjell 	/* proto */
100014a9b182Skjell 	if (!strcmp(w, "proto")) {
100114a9b182Skjell 		w = next_word(&l);
100214a9b182Skjell 		if (!strcmp(w, "tcp"))
100314a9b182Skjell 			rdr->proto = IPPROTO_TCP;
100414a9b182Skjell 		else if (!strcmp(w, "udp"))
100514a9b182Skjell 			rdr->proto = IPPROTO_UDP;
100614a9b182Skjell 		else {
10076329fa59Sderaadt 			error(n, "expected tcp/udp, got %s\n", w);
1008dbfb98deSprovos 			return (0);
100914a9b182Skjell 		}
101014a9b182Skjell 		w = next_word(&l);
101114a9b182Skjell 	}
101214a9b182Skjell 
101314a9b182Skjell 	/* no further options expected */
101414a9b182Skjell 	while (*w) {
10156329fa59Sderaadt 		error(n, "unexpected %s\n", w);
101614a9b182Skjell 		w = next_word(&l);
101714a9b182Skjell 	}
101814a9b182Skjell 
1019dbfb98deSprovos 	return (1);
102014a9b182Skjell }
1021