xref: /openbsd/sbin/pfctl/pfctl_parser.c (revision 252d784a)
1*252d784aSderaadt /*	$OpenBSD: pfctl_parser.c,v 1.3 2001/06/24 23:16:36 deraadt 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 
33*252d784aSderaadt #include <sys/types.h>
34*252d784aSderaadt #include <sys/socket.h>
35*252d784aSderaadt #include <net/if.h>
36*252d784aSderaadt #include <netinet/in.h>
37*252d784aSderaadt #include <net/pfvar.h>
38*252d784aSderaadt 
3914a9b182Skjell #include <stdio.h>
4014a9b182Skjell #include <stdlib.h>
4114a9b182Skjell #include <string.h>
4214a9b182Skjell #include <ctype.h>
4314a9b182Skjell #include <netdb.h>
4414a9b182Skjell 
4514a9b182Skjell #include "pfctl_parser.h"
4614a9b182Skjell 
4714a9b182Skjell static void		 print_addr (u_int32_t);
48*252d784aSderaadt static void		 print_host (struct state_host *);
49*252d784aSderaadt static void		 print_seq (struct state_peer *);
5014a9b182Skjell static void		 print_port (u_int8_t, u_int16_t, u_int16_t, char *);
5114a9b182Skjell static void		 print_flags (u_int8_t);
5214a9b182Skjell static char		*next_word (char **);
5314a9b182Skjell static u_int16_t	 next_number (char **);
5414a9b182Skjell static u_int32_t	 next_addr (char **);
5514a9b182Skjell static u_int8_t		 next_flags (char **);
5614a9b182Skjell static u_int16_t	 rule_port (char *, u_int8_t);
5714a9b182Skjell static u_int32_t	 rule_mask (u_int8_t);
5814a9b182Skjell 
5914a9b182Skjell static char *tcpflags = "FSRPAU";
6014a9b182Skjell 
6114a9b182Skjell static void
6214a9b182Skjell print_addr(u_int32_t a)
6314a9b182Skjell {
6414a9b182Skjell 	a = ntohl(a);
6514a9b182Skjell 	printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255);
6614a9b182Skjell }
6714a9b182Skjell 
6814a9b182Skjell static void
69*252d784aSderaadt print_host(struct state_host *h)
7014a9b182Skjell {
7114a9b182Skjell 	u_int32_t a = ntohl(h->addr);
7214a9b182Skjell 	u_int16_t p = ntohs(h->port);
7314a9b182Skjell 	printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, p);
7414a9b182Skjell }
7514a9b182Skjell 
7614a9b182Skjell static void
77*252d784aSderaadt print_seq(struct state_peer *p)
7814a9b182Skjell {
7914a9b182Skjell 	printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo);
8014a9b182Skjell }
8114a9b182Skjell 
8214a9b182Skjell static void
8314a9b182Skjell print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
8414a9b182Skjell {
8514a9b182Skjell 	struct servent *s = getservbyport(p1, proto);
8614a9b182Skjell 	p1 = ntohs(p1);
8714a9b182Skjell 	p2 = ntohs(p2);
8814a9b182Skjell 	printf("port ");
8914a9b182Skjell 	if (op == 1)
9014a9b182Skjell 		printf("%u >< %u ", p1, p2);
9114a9b182Skjell 	else if (op == 2) {
9214a9b182Skjell 		if (s != NULL)
9314a9b182Skjell 			printf("= %s ", s->s_name);
9414a9b182Skjell 		else
9514a9b182Skjell 			printf("= %u ", p1);
9614a9b182Skjell 	}
9714a9b182Skjell 	else if (op == 3) {
9814a9b182Skjell 		if (s != NULL)
9914a9b182Skjell 			printf("!= %s ", s->s_name);
10014a9b182Skjell 		else
10114a9b182Skjell 			printf("!= %u ", p1);
10214a9b182Skjell 	}
10314a9b182Skjell 	else if (op == 4)
10414a9b182Skjell 		printf("< %u ", p1);
10514a9b182Skjell 	else if (op == 5)
10614a9b182Skjell 		printf("<= %u ", p1);
10714a9b182Skjell 	else if (op == 6)
10814a9b182Skjell 		printf("> %u ", p1);
10914a9b182Skjell 	else
11014a9b182Skjell 		printf(">= %u ", p1);
11114a9b182Skjell }
11214a9b182Skjell 
11314a9b182Skjell static void
11414a9b182Skjell print_flags(u_int8_t f)
11514a9b182Skjell {
11614a9b182Skjell 	int i;
11714a9b182Skjell 	for (i = 0; i < 6; ++i)
11814a9b182Skjell 		if (f & (1 << i))
11914a9b182Skjell 			printf("%c", tcpflags[i]);
12014a9b182Skjell }
12114a9b182Skjell 
12214a9b182Skjell void
12314a9b182Skjell print_nat(struct nat *n)
12414a9b182Skjell {
12514a9b182Skjell 	printf("nat %s ", n->ifname);
12614a9b182Skjell 	if (n->not)
12714a9b182Skjell 		printf("! ");
12814a9b182Skjell 	print_addr(n->saddr);
12914a9b182Skjell 	if (n->smask != 0xFFFFFFFF) {
13014a9b182Skjell 		printf("/");
13114a9b182Skjell 		print_addr(n->smask);
13214a9b182Skjell 	}
13314a9b182Skjell 	printf(" -> ");
13414a9b182Skjell 	print_addr(n->daddr);
13514a9b182Skjell 	switch (n->proto) {
13614a9b182Skjell 	case IPPROTO_TCP:
13714a9b182Skjell 		printf(" proto tcp");
13814a9b182Skjell 		break;
13914a9b182Skjell 	case IPPROTO_UDP:
14014a9b182Skjell 		printf(" proto udp");
14114a9b182Skjell 		break;
14214a9b182Skjell 	case IPPROTO_ICMP:
14314a9b182Skjell 		printf(" proto icmp");
14414a9b182Skjell 		break;
14514a9b182Skjell 	}
14614a9b182Skjell 	printf("\n");
14714a9b182Skjell }
14814a9b182Skjell 
14914a9b182Skjell void
15014a9b182Skjell print_rdr(struct rdr *r)
15114a9b182Skjell {
15214a9b182Skjell 	printf("rdr %s ", r->ifname);
15314a9b182Skjell 	if (r->not)
15414a9b182Skjell 		printf("! ");
15514a9b182Skjell 	print_addr(r->daddr);
15614a9b182Skjell 	if (r->dmask != 0xFFFFFFFF) {
15714a9b182Skjell 		printf("/");
15814a9b182Skjell 		print_addr(r->dmask);
15914a9b182Skjell 	}
16014a9b182Skjell 	printf(" port %u -> ", ntohs(r->dport));
16114a9b182Skjell 	print_addr(r->raddr);
16214a9b182Skjell 	printf(" port %u", ntohs(r->rport));
16314a9b182Skjell 	switch (r->proto) {
16414a9b182Skjell 	case IPPROTO_TCP:
16514a9b182Skjell 		printf(" proto tcp");
16614a9b182Skjell 		break;
16714a9b182Skjell 	case IPPROTO_UDP:
16814a9b182Skjell 		printf(" proto udp");
16914a9b182Skjell 		break;
17014a9b182Skjell 	}
17114a9b182Skjell 	printf("\n");
17214a9b182Skjell }
17314a9b182Skjell 
17414a9b182Skjell void
17514a9b182Skjell print_status(struct status *s)
17614a9b182Skjell {
17714a9b182Skjell 	time_t t = time(NULL);
17814a9b182Skjell 	printf("%u %u %u", t, s->since, s->running);
17914a9b182Skjell 	if (s->running) {
18014a9b182Skjell 		printf(" %u %u", s->bytes[0], s->bytes[1]);
18114a9b182Skjell 		printf(" %u %u", s->packets[0][0], s->packets[0][1]);
18214a9b182Skjell 		printf(" %u %u", s->packets[1][0], s->packets[1][1]);
18314a9b182Skjell 		printf(" %u %u %u %u", s->states, s->state_inserts,
18414a9b182Skjell 		    s->state_removals, s->state_searches);
18514a9b182Skjell 	}
18614a9b182Skjell 	printf("\n");
18714a9b182Skjell }
18814a9b182Skjell 
18914a9b182Skjell void
19014a9b182Skjell print_state(struct state *s)
19114a9b182Skjell {
192*252d784aSderaadt 	struct state_peer *src, *dst;
19314a9b182Skjell 	u_int8_t hrs, min, sec;
194*252d784aSderaadt 
19514a9b182Skjell 	if (s->direction == PF_OUT) {
19614a9b182Skjell 		src = &s->src;
19714a9b182Skjell 		dst = &s->dst;
19814a9b182Skjell 	} else {
19914a9b182Skjell 		src = &s->dst;
20014a9b182Skjell 		dst = &s->src;
20114a9b182Skjell 	}
20214a9b182Skjell 	switch (s->proto) {
20314a9b182Skjell 	case IPPROTO_TCP:
20414a9b182Skjell 		printf("TCP  ");
20514a9b182Skjell 		break;
20614a9b182Skjell 	case IPPROTO_UDP:
20714a9b182Skjell 		printf("UDP  ");
20814a9b182Skjell 		break;
20914a9b182Skjell 	case IPPROTO_ICMP:
21014a9b182Skjell 		printf("ICMP ");
21114a9b182Skjell 		break;
21214a9b182Skjell 	default:
21314a9b182Skjell 		printf("???? ");
21414a9b182Skjell 		break;
21514a9b182Skjell 	}
21614a9b182Skjell 	if ((s->lan.addr != s->gwy.addr) || (s->lan.port != s->gwy.port)) {
21714a9b182Skjell 		print_host(&s->lan);
21814a9b182Skjell 		if (s->direction == PF_OUT)
21914a9b182Skjell 			printf(" -> ");
22014a9b182Skjell 		else
22114a9b182Skjell 			printf(" <- ");
22214a9b182Skjell 	}
22314a9b182Skjell 	print_host(&s->gwy);
22414a9b182Skjell 	if (s->direction == PF_OUT)
22514a9b182Skjell 		printf(" -> ");
22614a9b182Skjell 	else
22714a9b182Skjell 		printf(" <- ");
22814a9b182Skjell 	print_host(&s->ext);
22914a9b182Skjell 	printf("\n");
23014a9b182Skjell 
23114a9b182Skjell 	printf("%u:%u  ", src->state, dst->state);
23214a9b182Skjell 	if (s->proto == IPPROTO_TCP) {
23314a9b182Skjell 		print_seq(src);
23414a9b182Skjell 		printf("    ");
23514a9b182Skjell 		print_seq(dst);
23614a9b182Skjell 		printf("\n     ");
23714a9b182Skjell 	}
23814a9b182Skjell 
23914a9b182Skjell 	sec = s->creation % 60;
24014a9b182Skjell 	s->creation /= 60;
24114a9b182Skjell 	min = s->creation % 60;
24214a9b182Skjell 	s->creation /= 60;
24314a9b182Skjell 	hrs = s->creation;
24414a9b182Skjell 	printf("age %.2u:%.2u:%.2u", hrs, min, sec);
24514a9b182Skjell 	sec = s->expire % 60;
24614a9b182Skjell 	s->expire /= 60;
24714a9b182Skjell 	min = s->expire % 60;
24814a9b182Skjell 	s->expire /= 60;
24914a9b182Skjell 	hrs = s->expire;
25014a9b182Skjell 	printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec);
25114a9b182Skjell 	printf(", %u pkts, %u bytes\n", s->packets, s->bytes);
25214a9b182Skjell 	printf("\n");
25314a9b182Skjell }
25414a9b182Skjell 
25514a9b182Skjell void
25614a9b182Skjell print_rule(struct rule *r)
25714a9b182Skjell {
25814a9b182Skjell 	if (r->action == 0)
25914a9b182Skjell 		printf("pass ");
26014a9b182Skjell 	else
26114a9b182Skjell 		printf("block ");
26214a9b182Skjell 	if (r->action == 2)
26314a9b182Skjell 		printf("return-rst ");
26414a9b182Skjell 	if (r->direction == 0)
26514a9b182Skjell 		printf("in ");
26614a9b182Skjell 	else
26714a9b182Skjell 		printf("out ");
26814a9b182Skjell 	if (r->log)
26914a9b182Skjell 		printf("log ");
27014a9b182Skjell 	if (r->quick)
27114a9b182Skjell 		printf("quick ");
27214a9b182Skjell 	if (r->ifname[0])
27314a9b182Skjell 		printf("on %s ", r->ifname);
27414a9b182Skjell 	if (r->proto) {
27514a9b182Skjell 		struct protoent *p = getprotobynumber(r->proto);
27614a9b182Skjell 		if (p != NULL)
27714a9b182Skjell 			printf("proto %s ", p->p_name);
27814a9b182Skjell 		else
27914a9b182Skjell 			printf("proto %u ", r->proto);
28014a9b182Skjell 	}
28114a9b182Skjell 	if (!r->src.addr && !r->src.port_op && !r->dst.addr && !r->dst.port_op)
28214a9b182Skjell 		printf("all ");
28314a9b182Skjell 	else {
28414a9b182Skjell 		printf("from ");
28514a9b182Skjell 		if (!r->src.addr)
28614a9b182Skjell 			printf("any ");
28714a9b182Skjell 		else {
28814a9b182Skjell 			if (r->src.not)
28914a9b182Skjell 				printf("! ");
29014a9b182Skjell 			print_addr(r->src.addr);
29114a9b182Skjell 			if (r->src.mask != 0xFFFFFFFF) {
29214a9b182Skjell 				printf("/");
29314a9b182Skjell 				print_addr(r->src.mask);
29414a9b182Skjell 			}
29514a9b182Skjell 			printf(" ");
29614a9b182Skjell 		}
29714a9b182Skjell 		if (r->src.port_op)
29814a9b182Skjell 			print_port(r->src.port_op, r->src.port[0],
29914a9b182Skjell 			    r->src.port[1], r->proto == 6 ? "tcp" : "udp");
30014a9b182Skjell 
30114a9b182Skjell 		printf("to ");
30214a9b182Skjell 		if (!r->dst.addr)
30314a9b182Skjell 			printf("any ");
30414a9b182Skjell 		else {
30514a9b182Skjell 			if (r->dst.not)
30614a9b182Skjell 				printf("! ");
30714a9b182Skjell 			print_addr(r->dst.addr);
30814a9b182Skjell 			if (r->dst.mask != 0xFFFFFFFF) {
30914a9b182Skjell 				printf("/");
31014a9b182Skjell 				print_addr(r->dst.mask);
31114a9b182Skjell 			}
31214a9b182Skjell 			printf(" ");
31314a9b182Skjell 		}
31414a9b182Skjell 		if (r->dst.port_op)
31514a9b182Skjell 			print_port(r->dst.port_op, r->dst.port[0],
31614a9b182Skjell 			    r->dst.port[1], r->proto == 6 ? "tcp" : "udp");
31714a9b182Skjell 	}
31814a9b182Skjell 	if (r->flags || r->flagset) {
31914a9b182Skjell 		printf("flags ");
32014a9b182Skjell 		print_flags(r->flags);
32114a9b182Skjell 		printf("/");
32214a9b182Skjell 		print_flags(r->flagset);
32314a9b182Skjell 		printf(" ");
32414a9b182Skjell 	}
32514a9b182Skjell 	if (r->type)
32614a9b182Skjell 		printf("icmp-type %u ", r->type-1);
32714a9b182Skjell 	if (r->code)
32814a9b182Skjell 		printf("code %u ", r->code-1);
32914a9b182Skjell 	if (r->keep_state)
33014a9b182Skjell 		printf("keep state ");
33114a9b182Skjell 	printf("\n");
33214a9b182Skjell }
33314a9b182Skjell 
33414a9b182Skjell char *
33514a9b182Skjell next_line(char **s)
33614a9b182Skjell {
33714a9b182Skjell 	char *l;
33814a9b182Skjell 	l = *s;
33914a9b182Skjell 	while (**s && (**s != '\n'))
34014a9b182Skjell 		(*s)++;
34114a9b182Skjell 	if (**s) {
34214a9b182Skjell 		**s = 0;
34314a9b182Skjell 		(*s)++;
34414a9b182Skjell 	}
34514a9b182Skjell 	return l;
34614a9b182Skjell }
34714a9b182Skjell 
34814a9b182Skjell static char *
34914a9b182Skjell next_word(char **s)
35014a9b182Skjell {
35114a9b182Skjell 	char *w;
35214a9b182Skjell 	while ((**s == ' ') || (**s == '\t') || (**s == '\n'))
35314a9b182Skjell 		(*s)++;
35414a9b182Skjell 	w = *s;
35514a9b182Skjell 	while (**s && (**s != ' ') && (**s != '\t') && (**s != '\n'))
35614a9b182Skjell 		(*s)++;
35714a9b182Skjell 	if (**s) {
35814a9b182Skjell 		**s = 0;
35914a9b182Skjell 		(*s)++;
36014a9b182Skjell 	}
36114a9b182Skjell 	return w;
36214a9b182Skjell }
36314a9b182Skjell 
36414a9b182Skjell static u_int16_t
36514a9b182Skjell next_number(char **s)
36614a9b182Skjell {
36714a9b182Skjell 	u_int16_t n = 0;
36814a9b182Skjell 	while (**s && !isdigit(**s))
36914a9b182Skjell 		(*s)++;
37014a9b182Skjell 	while (**s && isdigit(**s)) {
37114a9b182Skjell 		n *= 10;
37214a9b182Skjell 		n += **s - '0';
37314a9b182Skjell 		(*s)++;
37414a9b182Skjell 	}
37514a9b182Skjell 	return n;
37614a9b182Skjell }
37714a9b182Skjell 
37814a9b182Skjell static u_int32_t
37914a9b182Skjell next_addr(char **w)
38014a9b182Skjell {
38114a9b182Skjell 	u_int8_t a, b, c, d;
38214a9b182Skjell 	a = next_number(w);
38314a9b182Skjell 	b = next_number(w);
38414a9b182Skjell 	c = next_number(w);
38514a9b182Skjell 	d = next_number(w);
38614a9b182Skjell 	return htonl((a << 24) | (b << 16) | (c << 8) | d);
38714a9b182Skjell }
38814a9b182Skjell 
38914a9b182Skjell static u_int8_t
39014a9b182Skjell next_flags(char **s)
39114a9b182Skjell {
39214a9b182Skjell 	u_int8_t f = 0;
39314a9b182Skjell 	char *p;
39414a9b182Skjell 	while (**s && !strchr(tcpflags, **s))
39514a9b182Skjell 		(*s)++;
39614a9b182Skjell 	while (**s && ((p = strchr(tcpflags, **s)) != NULL)) {
39714a9b182Skjell 		f |= 1 << (p-tcpflags);
39814a9b182Skjell 		(*s)++;
39914a9b182Skjell 	}
40014a9b182Skjell 	return f ? f : 63;
40114a9b182Skjell }
40214a9b182Skjell 
40314a9b182Skjell static u_int16_t
40414a9b182Skjell rule_port(char *w, u_int8_t p)
40514a9b182Skjell {
40614a9b182Skjell 	struct servent *s;
40714a9b182Skjell 	if (isdigit(*w))
40814a9b182Skjell 		return htons(atoi(w));
40914a9b182Skjell 	s = getservbyname(w, p == 6 ? "tcp" : "udp");
41014a9b182Skjell 	if (s == NULL)
41114a9b182Skjell 		return 0;
41214a9b182Skjell 	return s->s_port;
41314a9b182Skjell }
41414a9b182Skjell 
41514a9b182Skjell static u_int32_t
41614a9b182Skjell rule_mask(u_int8_t b)
41714a9b182Skjell {
41814a9b182Skjell 	u_int32_t m = 0;
41914a9b182Skjell 	int i;
42014a9b182Skjell 	for (i = 31; i > 31-b; --i)
42114a9b182Skjell 		m |= (1 << i);
42214a9b182Skjell 	return htonl(m);
42314a9b182Skjell }
42414a9b182Skjell 
42514a9b182Skjell int
42614a9b182Skjell parse_rule(int n, char *l, struct rule *r)
42714a9b182Skjell {
42814a9b182Skjell 	char *w;
42914a9b182Skjell 	memset(r, 0, sizeof(struct rule));
43014a9b182Skjell 	w = next_word(&l);
43114a9b182Skjell 
43214a9b182Skjell 	/* pass / block */
43314a9b182Skjell 	if (!strcmp(w, "pass" ))
43414a9b182Skjell 		r->action = 0;
43514a9b182Skjell 	else if (!strcmp(w, "block"))
43614a9b182Skjell 		r->action = 1;
43714a9b182Skjell 	else {
43814a9b182Skjell 		fprintf(stderr, "error on line %i: expected pass/block, got %s\n",
43914a9b182Skjell 		    n, w);
44014a9b182Skjell 		return 0;
44114a9b182Skjell 	}
44214a9b182Skjell 	w = next_word(&l);
44314a9b182Skjell 
44414a9b182Skjell 	/* return-rst */
44514a9b182Skjell 	if ((r->action == 1) && !strcmp(w, "return-rst")) {
44614a9b182Skjell 		r->action = 2;
44714a9b182Skjell 		w = next_word(&l);
44814a9b182Skjell 	}
44914a9b182Skjell 
45014a9b182Skjell 	/* in / out */
45114a9b182Skjell 	if (!strcmp(w, "in" ))
45214a9b182Skjell 		r->direction = 0;
45314a9b182Skjell 	else if (!strcmp(w, "out"))
45414a9b182Skjell 		r->direction = 1;
45514a9b182Skjell 	else {
45614a9b182Skjell 		fprintf(stderr, "error on line %i: expected in/out, got %s\n",
45714a9b182Skjell 		    n, w);
45814a9b182Skjell 		return 0;
45914a9b182Skjell 	}
46014a9b182Skjell 	w = next_word(&l);
46114a9b182Skjell 
46214a9b182Skjell 	/* log */
46314a9b182Skjell 	if (!strcmp(w, "log")) {
46414a9b182Skjell 		r->log = 1;
46514a9b182Skjell 		w = next_word(&l);
46614a9b182Skjell 	}
46714a9b182Skjell 
46814a9b182Skjell 	/* quick */
46914a9b182Skjell 	if (!strcmp(w, "quick")) {
47014a9b182Skjell 		r->quick = 1;
47114a9b182Skjell 		w = next_word(&l);
47214a9b182Skjell 	}
47314a9b182Skjell 
47414a9b182Skjell 	/* on <if> */
47514a9b182Skjell 	if (!strcmp(w, "on")) {
47614a9b182Skjell 		w = next_word(&l);
47714a9b182Skjell 		strncpy(r->ifname, w, 16);
47814a9b182Skjell 		w = next_word(&l);
47914a9b182Skjell 	}
48014a9b182Skjell 
48114a9b182Skjell 	/* proto tcp/udp/icmp */
48214a9b182Skjell 	if (!strcmp(w, "proto")) {
48314a9b182Skjell 		struct protoent *p;
48414a9b182Skjell 		w = next_word(&l);
48514a9b182Skjell 		p = getprotobyname(w);
48614a9b182Skjell 		if (p == NULL) {
48714a9b182Skjell 			fprintf(stderr, "error on line %i: unknown protocol %s\n",
48814a9b182Skjell 			    n, w);
48914a9b182Skjell 			return 0;
49014a9b182Skjell 		}
49114a9b182Skjell 		r->proto = p->p_proto;
49214a9b182Skjell 		w = next_word(&l);
49314a9b182Skjell 	}
49414a9b182Skjell 
49514a9b182Skjell 	/* all / from src to dst */
49614a9b182Skjell 	if (!strcmp(w, "all" ))
49714a9b182Skjell 		w = next_word(&l);
49814a9b182Skjell 	else if (!strcmp(w, "from")) {
49914a9b182Skjell 		w = next_word(&l);
50014a9b182Skjell 
50114a9b182Skjell 		/* source address */
50214a9b182Skjell 		if (!strcmp(w, "any"))
50314a9b182Skjell 			w = next_word(&l);
50414a9b182Skjell 		else {
50514a9b182Skjell 			if (!strcmp(w, "!")) {
50614a9b182Skjell 				r->src.not = 1;
50714a9b182Skjell 				w = next_word(&l);
50814a9b182Skjell 			}
50914a9b182Skjell 			r->src.addr = next_addr(&w);
51014a9b182Skjell 			if (!*w)
51114a9b182Skjell 				r->src.mask = 0xFFFFFFFF;
51214a9b182Skjell 			else if (*w == '/')
51314a9b182Skjell 				r->src.mask = rule_mask(next_number(&w));
51414a9b182Skjell 			else {
51514a9b182Skjell 				fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w);
51614a9b182Skjell 				return 0;
51714a9b182Skjell 			}
51814a9b182Skjell 			w = next_word(&l);
51914a9b182Skjell 		}
52014a9b182Skjell 
52114a9b182Skjell 		/* source port */
52214a9b182Skjell 		if (((r->proto == 6) || (r->proto == 17)) && !strcmp(w, "port")) {
52314a9b182Skjell 			w = next_word(&l);
52414a9b182Skjell 			if (!strcmp(w, "=" ))
52514a9b182Skjell 				r->src.port_op = 2;
52614a9b182Skjell 			else if (!strcmp(w, "!="))
52714a9b182Skjell 				r->src.port_op = 3;
52814a9b182Skjell 			else if (!strcmp(w, "<" ))
52914a9b182Skjell 				r->src.port_op = 4;
53014a9b182Skjell 			else if (!strcmp(w, "<="))
53114a9b182Skjell 				r->src.port_op = 5;
53214a9b182Skjell 			else if (!strcmp(w, ">" ))
53314a9b182Skjell 				r->src.port_op = 6;
53414a9b182Skjell 			else if (!strcmp(w, ">="))
53514a9b182Skjell 				r->src.port_op = 7;
53614a9b182Skjell 			else
53714a9b182Skjell 				r->src.port_op = 1;
53814a9b182Skjell 			if (r->src.port_op != 1)
53914a9b182Skjell 				w = next_word(&l);
54014a9b182Skjell 			r->src.port[0] = rule_port(w, r->proto);
54114a9b182Skjell 			w = next_word(&l);
54214a9b182Skjell 			if (r->src.port_op == 1) {
54314a9b182Skjell 				if (strcmp(w, "<>") && strcmp(w, "><")) {
54414a9b182Skjell 					fprintf(stderr, "error on line %i: expected <>/><, got %s\n", n, w);
54514a9b182Skjell 					return 0;
54614a9b182Skjell 				}
54714a9b182Skjell 				w = next_word(&l);
54814a9b182Skjell 				r->src.port[1] = rule_port(w, r->proto);
54914a9b182Skjell 				w = next_word(&l);
55014a9b182Skjell 			}
55114a9b182Skjell 		}
55214a9b182Skjell 
55314a9b182Skjell 		/* destination address */
55414a9b182Skjell 		if (strcmp(w, "to")) {
55514a9b182Skjell 			fprintf(stderr, "error on line %i: expected to, got %s\n",
55614a9b182Skjell 			    n, w);
55714a9b182Skjell 			return 0;
55814a9b182Skjell 		}
55914a9b182Skjell 		w = next_word(&l);
56014a9b182Skjell 		if (!strcmp(w, "any"))
56114a9b182Skjell 			w = next_word(&l);
56214a9b182Skjell 		else {
56314a9b182Skjell 			if (!strcmp(w, "!")) {
56414a9b182Skjell 				r->dst.not = 1;
56514a9b182Skjell 				w = next_word(&l);
56614a9b182Skjell 			}
56714a9b182Skjell 			r->dst.addr = next_addr(&w);
56814a9b182Skjell 			if (!*w)
56914a9b182Skjell 				r->dst.mask = 0xFFFFFFFF;
57014a9b182Skjell 			else if (*w == '/')
57114a9b182Skjell 				r->dst.mask = rule_mask(next_number(&w));
57214a9b182Skjell 			else {
57314a9b182Skjell 				fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w);
57414a9b182Skjell 				return 0;
57514a9b182Skjell 			}
57614a9b182Skjell 			w = next_word(&l);
57714a9b182Skjell 		}
57814a9b182Skjell 
57914a9b182Skjell 		/* destination port */
58014a9b182Skjell 		if (((r->proto == 6) || (r->proto == 17)) && !strcmp(w, "port")) {
58114a9b182Skjell 			w = next_word(&l);
58214a9b182Skjell 			if (!strcmp(w, "=" ))
58314a9b182Skjell 				r->dst.port_op = 2;
58414a9b182Skjell 			else if (!strcmp(w, "!="))
58514a9b182Skjell 				r->dst.port_op = 3;
58614a9b182Skjell 			else if (!strcmp(w, "<" ))
58714a9b182Skjell 				r->dst.port_op = 4;
58814a9b182Skjell 			else if (!strcmp(w, "<="))
58914a9b182Skjell 				r->dst.port_op = 5;
59014a9b182Skjell 			else if (!strcmp(w, ">" ))
59114a9b182Skjell 				r->dst.port_op = 6;
59214a9b182Skjell 			else if (!strcmp(w, ">="))
59314a9b182Skjell 				r->dst.port_op = 7;
59414a9b182Skjell 			else
59514a9b182Skjell 				r->dst.port_op = 1;
59614a9b182Skjell 			if (r->dst.port_op != 1)
59714a9b182Skjell 				w = next_word(&l);
59814a9b182Skjell 			r->dst.port[0] = rule_port(w, r->proto);
59914a9b182Skjell 			w = next_word(&l);
60014a9b182Skjell 			if (r->dst.port_op == 1) {
60114a9b182Skjell 				if (strcmp(w, "<>") && strcmp(w, "><")) {
60214a9b182Skjell 					fprintf(stderr, "error on line %i: expected <>/><, got %s\n", n, w);
60314a9b182Skjell 					return 0;
60414a9b182Skjell 				}
60514a9b182Skjell 				w = next_word(&l);
60614a9b182Skjell 				r->dst.port[1] = rule_port(w, r->proto);
60714a9b182Skjell 				w = next_word(&l);
60814a9b182Skjell 			}
60914a9b182Skjell 		}
61014a9b182Skjell 
61114a9b182Skjell 	}
61214a9b182Skjell 	else {
61314a9b182Skjell 		fprintf(stderr, "error on line %i: expected all/from, got %s\n",
61414a9b182Skjell 		    n, w);
61514a9b182Skjell 		return 0;
61614a9b182Skjell 	}
61714a9b182Skjell 
61814a9b182Skjell 	/* flags */
61914a9b182Skjell 	if (!strcmp(w, "flags")) {
62014a9b182Skjell 		if (r->proto != 6) {
62114a9b182Skjell 			fprintf(stderr, "error on line %i: flags only valid for proto tcp\n", n);
62214a9b182Skjell 			return 0;
62314a9b182Skjell 		}
62414a9b182Skjell 		else {
62514a9b182Skjell 			w = next_word(&l);
62614a9b182Skjell 			r->flags = next_flags(&w);
62714a9b182Skjell 			r->flagset = next_flags(&w);
62814a9b182Skjell 			w = next_word(&l);
62914a9b182Skjell 		}
63014a9b182Skjell 	}
63114a9b182Skjell 
63214a9b182Skjell 	/* icmp type/code */
63314a9b182Skjell 	if (!strcmp(w, "icmp-type")) {
63414a9b182Skjell 		if (r->proto != 1) {
63514a9b182Skjell 			fprintf(stderr, "error on line %i: icmp-type only valid for proto icmp\n", n);
63614a9b182Skjell 			return 0;
63714a9b182Skjell 		}
63814a9b182Skjell 		else {
63914a9b182Skjell 			w = next_word(&l);
64014a9b182Skjell 			r->type = atoi(w)+1;
64114a9b182Skjell 			w = next_word(&l);
64214a9b182Skjell 			if (!strcmp(w, "code")) {
64314a9b182Skjell 				w = next_word(&l);
64414a9b182Skjell 				r->code = atoi(w) + 1;
64514a9b182Skjell 				w = next_word(&l);
64614a9b182Skjell 			}
64714a9b182Skjell 		}
64814a9b182Skjell 	}
64914a9b182Skjell 
65014a9b182Skjell 	/* keep */
65114a9b182Skjell 	if (!strcmp(w, "keep")) {
65214a9b182Skjell 		w = next_word(&l);
65314a9b182Skjell 		if (!strcmp(w, "state")) {
65414a9b182Skjell 			w = next_word(&l);
65514a9b182Skjell 			r->keep_state = 1;
65614a9b182Skjell 		}
65714a9b182Skjell 		else {
65814a9b182Skjell 			fprintf(stderr, "error on line %i: expected state, got %s\n", n, w);
65914a9b182Skjell 			return 0;
66014a9b182Skjell 		}
66114a9b182Skjell 	}
66214a9b182Skjell 
66314a9b182Skjell 	/* no further options expected */
66414a9b182Skjell 	while (*w) {
66514a9b182Skjell 		fprintf(stderr, "error on line %i: unexpected %s\n", n, w);
66614a9b182Skjell 		w = next_word(&l);
66714a9b182Skjell 	}
66814a9b182Skjell 
66914a9b182Skjell 	return 1;
67014a9b182Skjell }
67114a9b182Skjell 
67214a9b182Skjell int
67314a9b182Skjell parse_nat(int n, char *l, struct nat *nat)
67414a9b182Skjell {
67514a9b182Skjell 	char *w;
67614a9b182Skjell 	memset(nat, 0, sizeof(struct nat));
67714a9b182Skjell 	w = next_word(&l);
67814a9b182Skjell 
67914a9b182Skjell 	/* nat */
68014a9b182Skjell 	if (strcmp(w, "nat" )) {
68114a9b182Skjell 		fprintf(stderr, "error on line %i: expected nat, got %s\n", n, w);
68214a9b182Skjell 		return 0;
68314a9b182Skjell 	}
68414a9b182Skjell 	w = next_word(&l);
68514a9b182Skjell 
68614a9b182Skjell 	/* if */
68714a9b182Skjell 	strncpy(nat->ifname, w, 16);
68814a9b182Skjell 	w = next_word(&l);
68914a9b182Skjell 
69014a9b182Skjell 	/* internal addr/mask */
69114a9b182Skjell 	if (!strcmp(w, "!")) {
69214a9b182Skjell 		nat->not = 1;
69314a9b182Skjell 		w = next_word(&l);
69414a9b182Skjell 	}
69514a9b182Skjell 	nat->saddr = next_addr(&w);
69614a9b182Skjell 	if (!*w)
69714a9b182Skjell 		nat->smask = 0xFFFFFFFF;
69814a9b182Skjell 	else if (*w == '/')
69914a9b182Skjell 		nat->smask = rule_mask(next_number(&w));
70014a9b182Skjell 	else {
70114a9b182Skjell 		fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w);
70214a9b182Skjell 		return 0;
70314a9b182Skjell 	}
70414a9b182Skjell 	w = next_word(&l);
70514a9b182Skjell 
70614a9b182Skjell 	/* -> */
70714a9b182Skjell 	if (strcmp(w, "->")) {
70814a9b182Skjell 		fprintf(stderr, "error on line %i: expected ->, got %s\n", n, w);
70914a9b182Skjell 		return 0;
71014a9b182Skjell 	}
71114a9b182Skjell 	w = next_word(&l);
71214a9b182Skjell 
71314a9b182Skjell 	/* external addr */
71414a9b182Skjell 	nat->daddr = next_addr(&w);
71514a9b182Skjell 	w = next_word(&l);
71614a9b182Skjell 
71714a9b182Skjell 	/* proto */
71814a9b182Skjell 	if (!strcmp(w, "proto")) {
71914a9b182Skjell 		w = next_word(&l);
72014a9b182Skjell 		if (!strcmp(w, "tcp"))
72114a9b182Skjell 			nat->proto = IPPROTO_TCP;
72214a9b182Skjell 		else if (!strcmp(w, "udp"))
72314a9b182Skjell 			nat->proto = IPPROTO_UDP;
72414a9b182Skjell 		else if (!strcmp(w, "icmp"))
72514a9b182Skjell 			nat->proto = IPPROTO_ICMP;
72614a9b182Skjell 		else {
72714a9b182Skjell 			fprintf(stderr,
72814a9b182Skjell 			 "error on line %i: expected tcp/udp/icmp, got %s\n",
72914a9b182Skjell 			    n, w);
73014a9b182Skjell 			return 0;
73114a9b182Skjell 		}
73214a9b182Skjell 		w = next_word(&l);
73314a9b182Skjell 	}
73414a9b182Skjell 
73514a9b182Skjell 	/* no further options expected */
73614a9b182Skjell 	while (*w) {
73714a9b182Skjell 		fprintf(stderr, "error on line %i: unexpected %s\n", n, w);
73814a9b182Skjell 		w = next_word(&l);
73914a9b182Skjell 	}
74014a9b182Skjell 
74114a9b182Skjell 	return 1;
74214a9b182Skjell }
74314a9b182Skjell 
74414a9b182Skjell int
74514a9b182Skjell parse_rdr(int n, char *l, struct rdr *rdr)
74614a9b182Skjell {
74714a9b182Skjell 	char *w;
74814a9b182Skjell 	memset(rdr, 0, sizeof(struct rdr));
74914a9b182Skjell 	w = next_word(&l);
75014a9b182Skjell 
75114a9b182Skjell 	/* rdr */
75214a9b182Skjell 	if (strcmp(w, "rdr" )) {
75314a9b182Skjell 		fprintf(stderr, "error on line %i: expected rdr, got %s\n", n, w);
75414a9b182Skjell 		return 0;
75514a9b182Skjell 	}
75614a9b182Skjell 	w = next_word(&l);
75714a9b182Skjell 
75814a9b182Skjell 	/* if */
75914a9b182Skjell 	strncpy(rdr->ifname, w, 16);
76014a9b182Skjell 	w = next_word(&l);
76114a9b182Skjell 
76214a9b182Skjell 	/* external addr/mask */
76314a9b182Skjell 	if (!strcmp(w, "!")) {
76414a9b182Skjell 		rdr->not = 1;
76514a9b182Skjell 		w = next_word(&l);
76614a9b182Skjell 	}
76714a9b182Skjell 	rdr->daddr = next_addr(&w);
76814a9b182Skjell 	if (!*w)
76914a9b182Skjell 		rdr->dmask = 0xFFFFFFFF;
77014a9b182Skjell 	else if (*w == '/')
77114a9b182Skjell 		rdr->dmask = rule_mask(next_number(&w));
77214a9b182Skjell 	else {
77314a9b182Skjell 		fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w);
77414a9b182Skjell 		return 0;
77514a9b182Skjell 	}
77614a9b182Skjell 	w = next_word(&l);
77714a9b182Skjell 
77814a9b182Skjell 	/* external port */
77914a9b182Skjell 	if (strcmp(w, "port")) {
78014a9b182Skjell 		fprintf(stderr, "error on line %i: expected port, got %s\n", n, w);
78114a9b182Skjell 		return 0;
78214a9b182Skjell 	}
78314a9b182Skjell 	w = next_word(&l);
78414a9b182Skjell 	rdr->dport = htons(next_number(&w));
78514a9b182Skjell 	w = next_word(&l);
78614a9b182Skjell 
78714a9b182Skjell 	/* -> */
78814a9b182Skjell 	if (strcmp(w, "->")) {
78914a9b182Skjell 		fprintf(stderr, "error on line %i: expected ->, got %s\n", n, w);
79014a9b182Skjell 		return 0;
79114a9b182Skjell 	}
79214a9b182Skjell 	w = next_word(&l);
79314a9b182Skjell 
79414a9b182Skjell 	/* internal addr */
79514a9b182Skjell 	rdr->raddr = next_addr(&w);
79614a9b182Skjell 	w = next_word(&l);
79714a9b182Skjell 
79814a9b182Skjell 	/* internal port */
79914a9b182Skjell 	if (strcmp(w, "port")) {
80014a9b182Skjell 		fprintf(stderr, "error on line %i: expected port, got %s\n", n, w);
80114a9b182Skjell 		return 0;
80214a9b182Skjell 	}
80314a9b182Skjell 	w = next_word(&l);
80414a9b182Skjell 	rdr->rport = htons(next_number(&w));
80514a9b182Skjell 	w = next_word(&l);
80614a9b182Skjell 
80714a9b182Skjell 	/* proto */
80814a9b182Skjell 	if (!strcmp(w, "proto")) {
80914a9b182Skjell 		w = next_word(&l);
81014a9b182Skjell 		if (!strcmp(w, "tcp"))
81114a9b182Skjell 			rdr->proto = IPPROTO_TCP;
81214a9b182Skjell 		else if (!strcmp(w, "udp"))
81314a9b182Skjell 			rdr->proto = IPPROTO_UDP;
81414a9b182Skjell 		else {
81514a9b182Skjell 			fprintf(stderr,
81614a9b182Skjell 			 "error on line %i: expected tcp/udp, got %s\n",
81714a9b182Skjell 			    n, w);
81814a9b182Skjell 			return 0;
81914a9b182Skjell 		}
82014a9b182Skjell 		w = next_word(&l);
82114a9b182Skjell 	}
82214a9b182Skjell 
82314a9b182Skjell 	/* no further options expected */
82414a9b182Skjell 	while (*w) {
82514a9b182Skjell 		fprintf(stderr, "error on line %i: unexpected %s\n", n, w);
82614a9b182Skjell 		w = next_word(&l);
82714a9b182Skjell 	}
82814a9b182Skjell 
82914a9b182Skjell 	return 1;
83014a9b182Skjell }
83114a9b182Skjell 
832