xref: /openbsd/sbin/pfctl/pfctl_parser.c (revision 64b4b616)
1*64b4b616Sfrantzen /*	$OpenBSD: pfctl_parser.c,v 1.173 2003/08/21 19:12:08 frantzen Exp $ */
214a9b182Skjell 
314a9b182Skjell /*
4fd3c3a0cSderaadt  * 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>
4030620b12Sfrantzen #include <netinet/icmp6.h>
41252d784aSderaadt #include <net/pfvar.h>
429f13c6caSmillert #include <arpa/inet.h>
43252d784aSderaadt 
4414a9b182Skjell #include <stdio.h>
4514a9b182Skjell #include <stdlib.h>
4614a9b182Skjell #include <string.h>
4714a9b182Skjell #include <ctype.h>
4814a9b182Skjell #include <netdb.h>
496329fa59Sderaadt #include <stdarg.h>
506329fa59Sderaadt #include <errno.h>
51ff352a37Smarkus #include <err.h>
5294e9410bShenning #include <ifaddrs.h>
5314a9b182Skjell 
5414a9b182Skjell #include "pfctl_parser.h"
55eb824e11Sderaadt #include "pfctl.h"
5614a9b182Skjell 
575d9ac2dcSdhartmei void		 print_op (u_int8_t, const char *, const char *);
58132c30ccShenning void		 print_port (u_int8_t, u_int16_t, u_int16_t, const char *);
591173271aScedric void		 print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
6081a15e5dSderaadt void		 print_flags (u_int8_t);
61*64b4b616Sfrantzen void		 print_fromto(struct pf_rule_addr *, pf_osfp_t,
62*64b4b616Sfrantzen 		    struct pf_rule_addr *, u_int8_t, u_int8_t, int);
6314a9b182Skjell 
64f2370d27Shenning struct node_host	*host_if(const char *, int);
65383ebbbfShenning struct node_host	*host_v4(const char *, int);
66f2370d27Shenning struct node_host	*host_v6(const char *, int);
67f2370d27Shenning struct node_host	*host_dns(const char *, int, int);
682a6c1abaShenning 
69361e311cShenning const char *tcpflags = "FSRPAUEW";
7014a9b182Skjell 
717d27d81aSdhartmei static const struct icmptypeent icmp_type[] = {
72082ebc44Swilfried 	{ "echoreq",	ICMP_ECHO },
73082ebc44Swilfried 	{ "echorep",	ICMP_ECHOREPLY },
74082ebc44Swilfried 	{ "unreach",	ICMP_UNREACH },
75082ebc44Swilfried 	{ "squench",	ICMP_SOURCEQUENCH },
76082ebc44Swilfried 	{ "redir",	ICMP_REDIRECT },
77082ebc44Swilfried 	{ "althost",	ICMP_ALTHOSTADDR },
78082ebc44Swilfried 	{ "routeradv",	ICMP_ROUTERADVERT },
79082ebc44Swilfried 	{ "routersol",	ICMP_ROUTERSOLICIT },
80082ebc44Swilfried 	{ "timex",	ICMP_TIMXCEED },
81082ebc44Swilfried 	{ "paramprob",	ICMP_PARAMPROB },
82082ebc44Swilfried 	{ "timereq",	ICMP_TSTAMP },
83082ebc44Swilfried 	{ "timerep",	ICMP_TSTAMPREPLY },
84082ebc44Swilfried 	{ "inforeq",	ICMP_IREQ },
85082ebc44Swilfried 	{ "inforep",	ICMP_IREQREPLY },
86082ebc44Swilfried 	{ "maskreq",	ICMP_MASKREQ },
8702cbcc9eSwilfried 	{ "maskrep",	ICMP_MASKREPLY },
8802cbcc9eSwilfried 	{ "trace",	ICMP_TRACEROUTE },
8902cbcc9eSwilfried 	{ "dataconv",	ICMP_DATACONVERR },
9002cbcc9eSwilfried 	{ "mobredir",	ICMP_MOBILE_REDIRECT },
9102cbcc9eSwilfried 	{ "ipv6-where",	ICMP_IPV6_WHEREAREYOU },
9202cbcc9eSwilfried 	{ "ipv6-here",	ICMP_IPV6_IAMHERE },
9302cbcc9eSwilfried 	{ "mobregreq",	ICMP_MOBILE_REGREQUEST },
9402cbcc9eSwilfried 	{ "mobregrep",	ICMP_MOBILE_REGREPLY },
9502cbcc9eSwilfried 	{ "skip",	ICMP_SKIP },
9602cbcc9eSwilfried 	{ "photuris",	ICMP_PHOTURIS }
97082ebc44Swilfried };
98082ebc44Swilfried 
997d27d81aSdhartmei static const struct icmptypeent icmp6_type[] = {
10030620b12Sfrantzen 	{ "unreach",	ICMP6_DST_UNREACH },
10130620b12Sfrantzen 	{ "toobig",	ICMP6_PACKET_TOO_BIG },
10230620b12Sfrantzen 	{ "timex",	ICMP6_TIME_EXCEEDED },
10330620b12Sfrantzen 	{ "paramprob",	ICMP6_PARAM_PROB },
10430620b12Sfrantzen 	{ "echoreq",	ICMP6_ECHO_REQUEST },
10530620b12Sfrantzen 	{ "echorep",	ICMP6_ECHO_REPLY },
10630620b12Sfrantzen 	{ "groupqry",	ICMP6_MEMBERSHIP_QUERY },
10722a58e88Sitojun 	{ "listqry",	MLD_LISTENER_QUERY },
10830620b12Sfrantzen 	{ "grouprep",	ICMP6_MEMBERSHIP_REPORT },
10922a58e88Sitojun 	{ "listenrep",	MLD_LISTENER_REPORT },
11030620b12Sfrantzen 	{ "groupterm",	ICMP6_MEMBERSHIP_REDUCTION },
11122a58e88Sitojun 	{ "listendone", MLD_LISTENER_DONE },
11230620b12Sfrantzen 	{ "routersol",	ND_ROUTER_SOLICIT },
11330620b12Sfrantzen 	{ "routeradv",	ND_ROUTER_ADVERT },
11430620b12Sfrantzen 	{ "neighbrsol", ND_NEIGHBOR_SOLICIT },
11530620b12Sfrantzen 	{ "neighbradv", ND_NEIGHBOR_ADVERT },
11630620b12Sfrantzen 	{ "redir",	ND_REDIRECT },
11730620b12Sfrantzen 	{ "routrrenum", ICMP6_ROUTER_RENUMBERING },
11830620b12Sfrantzen 	{ "wrureq",	ICMP6_WRUREQUEST },
11930620b12Sfrantzen 	{ "wrurep",	ICMP6_WRUREPLY },
12030620b12Sfrantzen 	{ "fqdnreq",	ICMP6_FQDN_QUERY },
12130620b12Sfrantzen 	{ "fqdnrep",	ICMP6_FQDN_REPLY },
12230620b12Sfrantzen 	{ "niqry",	ICMP6_NI_QUERY },
12330620b12Sfrantzen 	{ "nirep",	ICMP6_NI_REPLY },
12422a58e88Sitojun 	{ "mtraceresp",	MLD_MTRACE_RESP },
12522a58e88Sitojun 	{ "mtrace",	MLD_MTRACE }
12630620b12Sfrantzen };
12730620b12Sfrantzen 
1287d27d81aSdhartmei static const struct icmpcodeent icmp_code[] = {
129082ebc44Swilfried 	{ "net-unr",		ICMP_UNREACH,	ICMP_UNREACH_NET },
130082ebc44Swilfried 	{ "host-unr",		ICMP_UNREACH,	ICMP_UNREACH_HOST },
131082ebc44Swilfried 	{ "proto-unr",		ICMP_UNREACH,	ICMP_UNREACH_PROTOCOL },
132082ebc44Swilfried 	{ "port-unr",		ICMP_UNREACH,	ICMP_UNREACH_PORT },
133082ebc44Swilfried 	{ "needfrag",		ICMP_UNREACH,	ICMP_UNREACH_NEEDFRAG },
134082ebc44Swilfried 	{ "srcfail",		ICMP_UNREACH,	ICMP_UNREACH_SRCFAIL },
135082ebc44Swilfried 	{ "net-unk",		ICMP_UNREACH,	ICMP_UNREACH_NET_UNKNOWN },
136082ebc44Swilfried 	{ "host-unk",		ICMP_UNREACH,	ICMP_UNREACH_HOST_UNKNOWN },
137082ebc44Swilfried 	{ "isolate",		ICMP_UNREACH,	ICMP_UNREACH_ISOLATED },
138082ebc44Swilfried 	{ "net-prohib",		ICMP_UNREACH,	ICMP_UNREACH_NET_PROHIB },
139082ebc44Swilfried 	{ "host-prohib",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PROHIB },
140082ebc44Swilfried 	{ "net-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSNET },
141082ebc44Swilfried 	{ "host-tos",		ICMP_UNREACH,	ICMP_UNREACH_TOSHOST },
142082ebc44Swilfried 	{ "filter-prohib",	ICMP_UNREACH,	ICMP_UNREACH_FILTER_PROHIB },
143082ebc44Swilfried 	{ "host-preced",	ICMP_UNREACH,	ICMP_UNREACH_HOST_PRECEDENCE },
144082ebc44Swilfried 	{ "cutoff-preced",	ICMP_UNREACH,	ICMP_UNREACH_PRECEDENCE_CUTOFF },
145082ebc44Swilfried 	{ "redir-net",		ICMP_REDIRECT,	ICMP_REDIRECT_NET },
146082ebc44Swilfried 	{ "redir-host",		ICMP_REDIRECT,	ICMP_REDIRECT_HOST },
147082ebc44Swilfried 	{ "redir-tos-net",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSNET },
148082ebc44Swilfried 	{ "redir-tos-host",	ICMP_REDIRECT,	ICMP_REDIRECT_TOSHOST },
14902cbcc9eSwilfried 	{ "normal-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
15002cbcc9eSwilfried 	{ "common-adv",		ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
151082ebc44Swilfried 	{ "transit",		ICMP_TIMXCEED,	ICMP_TIMXCEED_INTRANS },
152082ebc44Swilfried 	{ "reassemb",		ICMP_TIMXCEED,	ICMP_TIMXCEED_REASS },
153082ebc44Swilfried 	{ "badhead",		ICMP_PARAMPROB,	ICMP_PARAMPROB_ERRATPTR },
154082ebc44Swilfried 	{ "optmiss",		ICMP_PARAMPROB,	ICMP_PARAMPROB_OPTABSENT },
15502cbcc9eSwilfried 	{ "badlen",		ICMP_PARAMPROB,	ICMP_PARAMPROB_LENGTH },
15602cbcc9eSwilfried 	{ "unknown-ind",	ICMP_PHOTURIS,	ICMP_PHOTURIS_UNKNOWN_INDEX },
15702cbcc9eSwilfried 	{ "auth-fail",		ICMP_PHOTURIS,	ICMP_PHOTURIS_AUTH_FAILED },
15802cbcc9eSwilfried 	{ "decrypt-fail",	ICMP_PHOTURIS,	ICMP_PHOTURIS_DECRYPT_FAILED }
159082ebc44Swilfried };
160082ebc44Swilfried 
1617d27d81aSdhartmei static const struct icmpcodeent icmp6_code[] = {
1621d32ee3bSdhartmei 	{ "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
1631d32ee3bSdhartmei 	{ "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
16430620b12Sfrantzen 	{ "notnbr-unr",	ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR },
16530620b12Sfrantzen 	{ "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
16630620b12Sfrantzen 	{ "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
16730620b12Sfrantzen 	{ "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
16830620b12Sfrantzen 	{ "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
16930620b12Sfrantzen 	{ "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
17030620b12Sfrantzen 	{ "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
17130620b12Sfrantzen 	{ "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
17230620b12Sfrantzen 	{ "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
17330620b12Sfrantzen 	{ "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER }
17430620b12Sfrantzen };
17530620b12Sfrantzen 
176d593fb91Sdrahn const struct pf_timeout pf_timeouts[] = {
177d593fb91Sdrahn 	{ "tcp.first",		PFTM_TCP_FIRST_PACKET },
178d593fb91Sdrahn 	{ "tcp.opening",	PFTM_TCP_OPENING },
179d593fb91Sdrahn 	{ "tcp.established",	PFTM_TCP_ESTABLISHED },
180d593fb91Sdrahn 	{ "tcp.closing",	PFTM_TCP_CLOSING },
181d593fb91Sdrahn 	{ "tcp.finwait",	PFTM_TCP_FIN_WAIT },
182d593fb91Sdrahn 	{ "tcp.closed",		PFTM_TCP_CLOSED },
183d593fb91Sdrahn 	{ "udp.first",		PFTM_UDP_FIRST_PACKET },
184d593fb91Sdrahn 	{ "udp.single",		PFTM_UDP_SINGLE },
185d593fb91Sdrahn 	{ "udp.multiple",	PFTM_UDP_MULTIPLE },
186d593fb91Sdrahn 	{ "icmp.first",		PFTM_ICMP_FIRST_PACKET },
187d593fb91Sdrahn 	{ "icmp.error",		PFTM_ICMP_ERROR_REPLY },
188d593fb91Sdrahn 	{ "other.first",	PFTM_OTHER_FIRST_PACKET },
189d593fb91Sdrahn 	{ "other.single",	PFTM_OTHER_SINGLE },
190d593fb91Sdrahn 	{ "other.multiple",	PFTM_OTHER_MULTIPLE },
191d593fb91Sdrahn 	{ "frag",		PFTM_FRAG },
192d593fb91Sdrahn 	{ "interval",		PFTM_INTERVAL },
193a85e74a5Sdhartmei 	{ "adaptive.start",	PFTM_ADAPTIVE_START },
194a85e74a5Sdhartmei 	{ "adaptive.end",	PFTM_ADAPTIVE_END },
195d593fb91Sdrahn 	{ NULL,			0 }
196d593fb91Sdrahn };
197d593fb91Sdrahn 
1987d27d81aSdhartmei const struct icmptypeent *
199bb9f691eSmcbride geticmptypebynumber(u_int8_t type, sa_family_t af)
200082ebc44Swilfried {
201ed99c291Sderaadt 	unsigned int	i;
202082ebc44Swilfried 
203d14c53d7Swilfried 	if (af != AF_INET6) {
204e4ebe044Shenning 		for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0]));
205e4ebe044Shenning 		    i++) {
206082ebc44Swilfried 			if (type == icmp_type[i].type)
207082ebc44Swilfried 				return (&icmp_type[i]);
208082ebc44Swilfried 		}
20930620b12Sfrantzen 	} else {
21030620b12Sfrantzen 		for (i=0; i < (sizeof (icmp6_type) /
21130620b12Sfrantzen 		    sizeof(icmp6_type[0])); i++) {
21230620b12Sfrantzen 			if (type == icmp6_type[i].type)
21330620b12Sfrantzen 				 return (&icmp6_type[i]);
21430620b12Sfrantzen 		}
21530620b12Sfrantzen 	}
21630620b12Sfrantzen 	return (NULL);
217082ebc44Swilfried }
218082ebc44Swilfried 
2197d27d81aSdhartmei const struct icmptypeent *
220bb9f691eSmcbride geticmptypebyname(char *w, sa_family_t af)
221082ebc44Swilfried {
222ed99c291Sderaadt 	unsigned int	i;
223082ebc44Swilfried 
224d14c53d7Swilfried 	if (af != AF_INET6) {
225e4ebe044Shenning 		for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0]));
226e4ebe044Shenning 		    i++) {
227082ebc44Swilfried 			if (!strcmp(w, icmp_type[i].name))
228082ebc44Swilfried 				return (&icmp_type[i]);
229082ebc44Swilfried 		}
23030620b12Sfrantzen 	} else {
23130620b12Sfrantzen 		for (i=0; i < (sizeof (icmp6_type) /
23230620b12Sfrantzen 		    sizeof(icmp6_type[0])); i++) {
23330620b12Sfrantzen 			if (!strcmp(w, icmp6_type[i].name))
23430620b12Sfrantzen 				return (&icmp6_type[i]);
23530620b12Sfrantzen 		}
23630620b12Sfrantzen 	}
23730620b12Sfrantzen 	return (NULL);
238082ebc44Swilfried }
239082ebc44Swilfried 
2407d27d81aSdhartmei const struct icmpcodeent *
241bb9f691eSmcbride geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
242082ebc44Swilfried {
243ed99c291Sderaadt 	unsigned int	i;
244082ebc44Swilfried 
245d14c53d7Swilfried 	if (af != AF_INET6) {
246e4ebe044Shenning 		for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0]));
247e4ebe044Shenning 		    i++) {
24830620b12Sfrantzen 			if (type == icmp_code[i].type &&
24930620b12Sfrantzen 			    code == icmp_code[i].code)
250082ebc44Swilfried 				return (&icmp_code[i]);
251082ebc44Swilfried 		}
25230620b12Sfrantzen 	} else {
25330620b12Sfrantzen 		for (i=0; i < (sizeof (icmp6_code) /
25430620b12Sfrantzen 		   sizeof(icmp6_code[0])); i++) {
25530620b12Sfrantzen 			if (type == icmp6_code[i].type &&
25630620b12Sfrantzen 			    code == icmp6_code[i].code)
25730620b12Sfrantzen 				return (&icmp6_code[i]);
25830620b12Sfrantzen 		}
25930620b12Sfrantzen 	}
26030620b12Sfrantzen 	return (NULL);
261082ebc44Swilfried }
262082ebc44Swilfried 
2637d27d81aSdhartmei const struct icmpcodeent *
264bb9f691eSmcbride geticmpcodebyname(u_long type, char *w, sa_family_t af)
265082ebc44Swilfried {
266ed99c291Sderaadt 	unsigned int	i;
267082ebc44Swilfried 
268d14c53d7Swilfried 	if (af != AF_INET6) {
269e4ebe044Shenning 		for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0]));
270e4ebe044Shenning 		    i++) {
27130620b12Sfrantzen 			if (type == icmp_code[i].type &&
27230620b12Sfrantzen 			    !strcmp(w, icmp_code[i].name))
273082ebc44Swilfried 				return (&icmp_code[i]);
274082ebc44Swilfried 		}
27530620b12Sfrantzen 	} else {
27630620b12Sfrantzen 		for (i=0; i < (sizeof (icmp6_code) /
27730620b12Sfrantzen 		    sizeof(icmp6_code[0])); i++) {
27830620b12Sfrantzen 			if (type == icmp6_code[i].type &&
27930620b12Sfrantzen 			    !strcmp(w, icmp6_code[i].name))
28030620b12Sfrantzen 				return (&icmp6_code[i]);
28130620b12Sfrantzen 		}
28230620b12Sfrantzen 	}
28330620b12Sfrantzen 	return (NULL);
28430620b12Sfrantzen }
28530620b12Sfrantzen 
28681a15e5dSderaadt void
2875d9ac2dcSdhartmei print_op(u_int8_t op, const char *a1, const char *a2)
2885d9ac2dcSdhartmei {
2895d9ac2dcSdhartmei 	if (op == PF_OP_IRG)
2905d9ac2dcSdhartmei 		printf(" %s >< %s", a1, a2);
2915d9ac2dcSdhartmei 	else if (op == PF_OP_XRG)
2925d9ac2dcSdhartmei 		printf(" %s <> %s", a1, a2);
2931308506cShenning 	else if (op == PF_OP_EQ)
2945d9ac2dcSdhartmei 		printf(" = %s", a1);
2951308506cShenning 	else if (op == PF_OP_NE)
2965d9ac2dcSdhartmei 		printf(" != %s", a1);
2971308506cShenning 	else if (op == PF_OP_LT)
2985d9ac2dcSdhartmei 		printf(" < %s", a1);
2995d9ac2dcSdhartmei 	else if (op == PF_OP_LE)
3005d9ac2dcSdhartmei 		printf(" <= %s", a1);
3015d9ac2dcSdhartmei 	else if (op == PF_OP_GT)
3025d9ac2dcSdhartmei 		printf(" > %s", a1);
3035d9ac2dcSdhartmei 	else if (op == PF_OP_GE)
3045d9ac2dcSdhartmei 		printf(" >= %s", a1);
3058da4e377Smcbride 	else if (op == PF_OP_RRG)
3068da4e377Smcbride 		printf(" %s:%s", a1, a2);
3075d9ac2dcSdhartmei }
3085d9ac2dcSdhartmei 
3095d9ac2dcSdhartmei void
310132c30ccShenning print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto)
31114a9b182Skjell {
312e31d21c9Sdhartmei 	char		 a1[6], a2[6];
313e4ebe044Shenning 	struct servent	*s;
31481a15e5dSderaadt 
315e4ebe044Shenning 	s = getservbyport(p1, proto);
31614a9b182Skjell 	p1 = ntohs(p1);
31714a9b182Skjell 	p2 = ntohs(p2);
3185d9ac2dcSdhartmei 	snprintf(a1, sizeof(a1), "%u", p1);
3195d9ac2dcSdhartmei 	snprintf(a2, sizeof(a2), "%u", p2);
32014a9b182Skjell 	printf(" port");
3215d9ac2dcSdhartmei 	if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
3225d9ac2dcSdhartmei 		print_op(op, s->s_name, a2);
32314a9b182Skjell 	else
3245d9ac2dcSdhartmei 		print_op(op, a1, a2);
3255d9ac2dcSdhartmei }
3265d9ac2dcSdhartmei 
3275d9ac2dcSdhartmei void
3281173271aScedric print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
3295d9ac2dcSdhartmei {
330d8fcd2dfSdhartmei 	char	a1[11], a2[11];
3315d9ac2dcSdhartmei 
3325d9ac2dcSdhartmei 	snprintf(a1, sizeof(a1), "%u", u1);
3335d9ac2dcSdhartmei 	snprintf(a2, sizeof(a2), "%u", u2);
3345d9ac2dcSdhartmei 	printf(" %s", t);
3351173271aScedric 	if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
336c16ab608Sdhartmei 		print_op(op, "unknown", a2);
337c16ab608Sdhartmei 	else
338c16ab608Sdhartmei 		print_op(op, a1, a2);
339c16ab608Sdhartmei }
340c16ab608Sdhartmei 
341c16ab608Sdhartmei void
34214a9b182Skjell print_flags(u_int8_t f)
34314a9b182Skjell {
34414a9b182Skjell 	int	i;
34581a15e5dSderaadt 
346bc795af0Shugh 	for (i = 0; tcpflags[i]; ++i)
34714a9b182Skjell 		if (f & (1 << i))
34814a9b182Skjell 			printf("%c", tcpflags[i]);
34914a9b182Skjell }
35014a9b182Skjell 
35114a9b182Skjell void
352*64b4b616Sfrantzen print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst,
35344f5ed0aScedric     sa_family_t af, u_int8_t proto, int verbose)
35415e76891Sdhartmei {
355*64b4b616Sfrantzen 	char buf[PF_OSFP_LEN*3];
3561173271aScedric 	if (src->addr.type == PF_ADDR_ADDRMASK &&
3571173271aScedric 	    dst->addr.type == PF_ADDR_ADDRMASK &&
358bcf142a4Sdhartmei 	    PF_AZERO(&src->addr.v.a.addr, AF_INET6) &&
359bcf142a4Sdhartmei 	    PF_AZERO(&src->addr.v.a.mask, AF_INET6) &&
3601173271aScedric 	    PF_AZERO(&dst->addr.v.a.addr, AF_INET6) &&
3611173271aScedric 	    PF_AZERO(&dst->addr.v.a.mask, AF_INET6) &&
3621173271aScedric 	    !src->not && !dst->not &&
363*64b4b616Sfrantzen 	    !src->port_op && !dst->port_op &&
364*64b4b616Sfrantzen 	    osfp == PF_OSFP_ANY)
36515e76891Sdhartmei 		printf(" all");
36615e76891Sdhartmei 	else {
36715e76891Sdhartmei 		printf(" from ");
36815e76891Sdhartmei 		if (src->not)
36915e76891Sdhartmei 			printf("! ");
37044f5ed0aScedric 		print_addr(&src->addr, af, verbose);
37115e76891Sdhartmei 		if (src->port_op)
37215e76891Sdhartmei 			print_port(src->port_op, src->port[0],
37315e76891Sdhartmei 			    src->port[1],
37415e76891Sdhartmei 			    proto == IPPROTO_TCP ? "tcp" : "udp");
375*64b4b616Sfrantzen 		if (osfp != PF_OSFP_ANY)
376*64b4b616Sfrantzen 			printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf,
377*64b4b616Sfrantzen 			    sizeof(buf)));
37815e76891Sdhartmei 
37915e76891Sdhartmei 		printf(" to ");
38015e76891Sdhartmei 		if (dst->not)
38115e76891Sdhartmei 			printf("! ");
38244f5ed0aScedric 		print_addr(&dst->addr, af, verbose);
38315e76891Sdhartmei 		if (dst->port_op)
38415e76891Sdhartmei 			print_port(dst->port_op, dst->port[0],
38515e76891Sdhartmei 			    dst->port[1],
38615e76891Sdhartmei 			    proto == IPPROTO_TCP ? "tcp" : "udp");
38715e76891Sdhartmei 	}
38815e76891Sdhartmei }
38915e76891Sdhartmei 
39015e76891Sdhartmei void
391e0c302d0Smcbride print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2,
392e0c302d0Smcbride     sa_family_t af, int id)
3933a44df3cSmcbride {
3943a44df3cSmcbride 	struct pf_pooladdr	*pooladdr;
3953a44df3cSmcbride 
3966c917913Smcbride 	if ((TAILQ_FIRST(&pool->list) != NULL) &&
3976c917913Smcbride 	    TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
3983a44df3cSmcbride 		printf("{ ");
3993a44df3cSmcbride 	TAILQ_FOREACH(pooladdr, &pool->list, entries){
4003a44df3cSmcbride 		switch (id) {
401e8793aa9Smcbride 		case PF_NAT:
402e8793aa9Smcbride 		case PF_RDR:
403e8793aa9Smcbride 		case PF_BINAT:
40420b4324fScedric 			print_addr(&pooladdr->addr, af, 0);
4053a44df3cSmcbride 			break;
406e8793aa9Smcbride 		case PF_PASS:
40720b4324fScedric 			if (PF_AZERO(&pooladdr->addr.v.a.addr, af))
4083b9b234fSmcbride 				printf("%s", pooladdr->ifname);
409790504a6Sdhartmei 			else {
4103a44df3cSmcbride 				printf("(%s ", pooladdr->ifname);
41120b4324fScedric 				print_addr(&pooladdr->addr, af, 0);
4123a44df3cSmcbride 				printf(")");
4133b9b234fSmcbride 			}
4143a44df3cSmcbride 			break;
415e8793aa9Smcbride 		default:
416e8793aa9Smcbride 			break;
4173a44df3cSmcbride 		}
4183a44df3cSmcbride 		if (TAILQ_NEXT(pooladdr, entries) != NULL)
4193a44df3cSmcbride 			printf(", ");
4203a44df3cSmcbride 		else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
4213a44df3cSmcbride 			printf(" }");
4223a44df3cSmcbride 	}
423e0c302d0Smcbride 	switch (id) {
424e8793aa9Smcbride 	case PF_NAT:
4259782f7a2Smcbride 		if ((p1 != PF_NAT_PROXY_PORT_LOW ||
4269782f7a2Smcbride 		    p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) {
427e0c302d0Smcbride 			if (p1 == p2)
428e0c302d0Smcbride 				printf(" port %u", p1);
429e0c302d0Smcbride 			else
430e0c302d0Smcbride 				printf(" port %u:%u", p1, p2);
431e0c302d0Smcbride 		}
432e0c302d0Smcbride 		break;
433e8793aa9Smcbride 	case PF_RDR:
434e0c302d0Smcbride 		if (p1) {
4358da4e377Smcbride 			printf(" port %u", p1);
4368da4e377Smcbride 			if (p2 && (p2 != p1))
4378da4e377Smcbride 				printf(":%u", p2);
438e0c302d0Smcbride 		}
439e0c302d0Smcbride 		break;
440e0c302d0Smcbride 	default:
441e0c302d0Smcbride 		break;
442e0c302d0Smcbride 	}
443e0c302d0Smcbride 	switch (pool->opts & PF_POOL_TYPEMASK) {
444e0c302d0Smcbride 	case PF_POOL_NONE:
445e0c302d0Smcbride 		break;
446e0c302d0Smcbride 	case PF_POOL_BITMASK:
447e0c302d0Smcbride 		printf(" bitmask");
448e0c302d0Smcbride 		break;
449e0c302d0Smcbride 	case PF_POOL_RANDOM:
450e0c302d0Smcbride 		printf(" random");
451e0c302d0Smcbride 		break;
452e0c302d0Smcbride 	case PF_POOL_SRCHASH:
4530436fa02Smcbride 		printf(" source-hash 0x%08x%08x%08x%08x",
454e0c302d0Smcbride 		    pool->key.key32[0], pool->key.key32[1],
455e0c302d0Smcbride 		    pool->key.key32[2], pool->key.key32[3]);
456e0c302d0Smcbride 		break;
457e0c302d0Smcbride 	case PF_POOL_ROUNDROBIN:
458e0c302d0Smcbride 		printf(" round-robin");
459e0c302d0Smcbride 		break;
460e0c302d0Smcbride 	}
4619782f7a2Smcbride 	if (id == PF_NAT && p1 == 0 && p2 == 0)
462e0c302d0Smcbride 		printf(" static-port");
4633a44df3cSmcbride }
4643a44df3cSmcbride 
465132c30ccShenning const char	*pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
466132c30ccShenning const char	*pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
46799a73934Sderaadt 
46814a9b182Skjell void
46981a15e5dSderaadt print_status(struct pf_status *s)
47014a9b182Skjell {
471e4ebe044Shenning 	char	statline[80];
472c474e331Shenning 	time_t	runtime;
47399a73934Sderaadt 	int	i;
47499a73934Sderaadt 
475c474e331Shenning 	runtime = time(NULL) - s->since;
476c474e331Shenning 
477d85e4ad6Sdhartmei 	if (s->running) {
478d85e4ad6Sdhartmei 		unsigned	sec, min, hrs, day = runtime;
479d85e4ad6Sdhartmei 
480d85e4ad6Sdhartmei 		sec = day % 60;
481d85e4ad6Sdhartmei 		day /= 60;
482d85e4ad6Sdhartmei 		min = day % 60;
483d85e4ad6Sdhartmei 		day /= 60;
484d85e4ad6Sdhartmei 		hrs = day % 24;
485d85e4ad6Sdhartmei 		day /= 24;
486c474e331Shenning 		snprintf(statline, sizeof(statline),
487d85e4ad6Sdhartmei 		    "Status: Enabled for %u days %.2u:%.2u:%.2u",
488d85e4ad6Sdhartmei 		    day, hrs, min, sec);
489d85e4ad6Sdhartmei 	} else
490c474e331Shenning 		snprintf(statline, sizeof(statline), "Status: Disabled");
491c97b4ee1Shenning 	printf("%-44s", statline);
492ae58c8acSdhartmei 	switch (s->debug) {
493ae58c8acSdhartmei 	case 0:
494c97b4ee1Shenning 		printf("%15s\n\n", "Debug: None");
495ae58c8acSdhartmei 		break;
496ae58c8acSdhartmei 	case 1:
497c97b4ee1Shenning 		printf("%15s\n\n", "Debug: Urgent");
498ae58c8acSdhartmei 		break;
499ae58c8acSdhartmei 	case 2:
500c97b4ee1Shenning 		printf("%15s\n\n", "Debug: Misc");
501ae58c8acSdhartmei 		break;
502ae58c8acSdhartmei 	}
503c474e331Shenning 	if (s->ifname[0] != 0) {
504c474e331Shenning 		printf("Interface Stats for %-16s %5s %16s\n",
505c474e331Shenning 		    s->ifname, "IPv4", "IPv6");
506c474e331Shenning 		printf("  %-25s %14llu %16llu\n", "Bytes In",
5077189e280Sdhartmei 		    s->bcounters[0][0], s->bcounters[1][0]);
508c474e331Shenning 		printf("  %-25s %14llu %16llu\n", "Bytes Out",
5097189e280Sdhartmei 		    s->bcounters[0][1], s->bcounters[1][1]);
510c474e331Shenning 		printf("  Packets In\n");
511c474e331Shenning 		printf("    %-23s %14llu %16llu\n", "Passed",
5127189e280Sdhartmei 		    s->pcounters[0][0][PF_PASS],
5137189e280Sdhartmei 		    s->pcounters[1][0][PF_PASS]);
514c474e331Shenning 		printf("    %-23s %14llu %16llu\n", "Blocked",
5157189e280Sdhartmei 		    s->pcounters[0][0][PF_DROP],
5167189e280Sdhartmei 		    s->pcounters[1][0][PF_DROP]);
517c474e331Shenning 		printf("  Packets Out\n");
518c474e331Shenning 		printf("    %-23s %14llu %16llu\n", "Passed",
5197189e280Sdhartmei 		    s->pcounters[0][1][PF_PASS],
5207189e280Sdhartmei 		    s->pcounters[1][1][PF_PASS]);
521c474e331Shenning 		printf("    %-23s %14llu %16llu\n\n", "Blocked",
5227189e280Sdhartmei 		    s->pcounters[0][1][PF_DROP],
5237189e280Sdhartmei 		    s->pcounters[1][1][PF_DROP]);
524c474e331Shenning 	}
525c474e331Shenning 	printf("%-27s %14s %16s\n", "State Table", "Total", "Rate");
526c474e331Shenning 	printf("  %-25s %14u %14s\n", "current entries", s->states, "");
527c474e331Shenning 	for (i = 0; i < FCNT_MAX; i++) {
528c474e331Shenning 		printf("  %-25s %14lld ", pf_fcounters[i],
52984976600Sderaadt 			    s->fcounters[i]);
530c474e331Shenning 		if (runtime > 0)
531c474e331Shenning 			printf("%14.1f/s\n",
532c474e331Shenning 			    (double)s->fcounters[i] / (double)runtime);
533c474e331Shenning 		else
534c474e331Shenning 			printf("%14s\n", "");
535c474e331Shenning 	}
53699a73934Sderaadt 	printf("Counters\n");
537c474e331Shenning 	for (i = 0; i < PFRES_MAX; i++) {
538c474e331Shenning 		printf("  %-25s %14lld ", pf_reasons[i],
53999a73934Sderaadt 		    s->counters[i]);
540c474e331Shenning 		if (runtime > 0)
541c474e331Shenning 			printf("%14.1f/s\n",
542c474e331Shenning 			    (double)s->counters[i] / (double)runtime);
543c474e331Shenning 		else
544c474e331Shenning 			printf("%14s\n", "");
545c474e331Shenning 	}
54614a9b182Skjell }
54714a9b182Skjell 
54814a9b182Skjell void
5491173271aScedric print_rule(struct pf_rule *r, int verbose)
55014a9b182Skjell {
5511173271aScedric 	static const char *actiontypes[] = { "pass", "block", "scrub", "nat",
5521173271aScedric 	    "no nat", "binat", "no binat", "rdr", "no rdr" };
5531173271aScedric 	static const char *anchortypes[] = { "anchor", "anchor", "anchor",
5541173271aScedric 	    "nat-anchor", "nat-anchor", "binat-anchor", "binat-anchor",
5551173271aScedric 	    "rdr-anchor", "rdr-anchor" };
556cc5f0329Sdhartmei 	int	i, opts;
557cc5f0329Sdhartmei 
55874dc4fddShenning 	if (verbose)
55978baf774Sdhartmei 		printf("@%d ", r->nr);
5601173271aScedric 	if (r->action > PF_NORDR)
5611173271aScedric 		printf("action(%d)", r->action);
5621173271aScedric 	else if (r->anchorname[0])
5631173271aScedric 		printf("%s %s", anchortypes[r->action], r->anchorname);
564fde34e86Shenning 	else {
5651173271aScedric 		printf("%s", actiontypes[r->action]);
566fde34e86Shenning 		if (r->natpass)
567fde34e86Shenning 			printf(" pass");
568fde34e86Shenning 	}
5691173271aScedric 	if (r->action == PF_DROP) {
5708a87542aShenning 		if (r->rule_flag & PFRULE_RETURN)
5718a87542aShenning 			printf(" return");
5728a87542aShenning 		else if (r->rule_flag & PFRULE_RETURNRST) {
5731f77cc8aSpb 			if (!r->return_ttl)
57414a9b182Skjell 				printf(" return-rst");
5751f77cc8aSpb 			else
5761f77cc8aSpb 				printf(" return-rst(ttl %d)", r->return_ttl);
577328b2decShenning 		} else if (r->rule_flag & PFRULE_RETURNICMP) {
578328b2decShenning 			const struct icmpcodeent	*ic, *ic6;
579b996d042Sdhartmei 
580b996d042Sdhartmei 			ic = geticmpcodebynumber(r->return_icmp >> 8,
581328b2decShenning 			    r->return_icmp & 255, AF_INET);
582328b2decShenning 			ic6 = geticmpcodebynumber(r->return_icmp6 >> 8,
583328b2decShenning 			    r->return_icmp6 & 255, AF_INET6);
584d14c53d7Swilfried 
585328b2decShenning 			switch(r->af) {
586328b2decShenning 			case AF_INET:
587328b2decShenning 				printf(" return-icmp");
588d14c53d7Swilfried 				if (ic == NULL)
589d14c53d7Swilfried 					printf("(%u)", r->return_icmp & 255);
590b996d042Sdhartmei 				else
591328b2decShenning 					printf("(%s)", ic->name);
592328b2decShenning 				break;
593328b2decShenning 			case AF_INET6:
594328b2decShenning 				printf(" return-icmp6");
595328b2decShenning 				if (ic6 == NULL)
596328b2decShenning 					printf("(%u)", r->return_icmp6 & 255);
597328b2decShenning 				else
598328b2decShenning 					printf("(%s)", ic6->name);
599328b2decShenning 				break;
600328b2decShenning 			default:
601328b2decShenning 				printf(" return-icmp");
602328b2decShenning 				if (ic == NULL)
603328b2decShenning 					printf("(%u, ", r->return_icmp & 255);
604328b2decShenning 				else
605328b2decShenning 					printf("(%s, ", ic->name);
606328b2decShenning 				if (ic6 == NULL)
607328b2decShenning 					printf("%u)", r->return_icmp6 & 255);
608328b2decShenning 				else
609328b2decShenning 					printf("%s)", ic6->name);
610328b2decShenning 				break;
611328b2decShenning 			}
612acf2444cShenning 		} else
613acf2444cShenning 			printf(" drop");
6141173271aScedric 	}
6157189e280Sdhartmei 	if (r->direction == PF_IN)
61614a9b182Skjell 		printf(" in");
6177189e280Sdhartmei 	else if (r->direction == PF_OUT)
61814a9b182Skjell 		printf(" out");
6197242ce7aSdhartmei 	if (r->log == 1)
62014a9b182Skjell 		printf(" log");
6217242ce7aSdhartmei 	else if (r->log == 2)
6227242ce7aSdhartmei 		printf(" log-all");
62314a9b182Skjell 	if (r->quick)
62414a9b182Skjell 		printf(" quick");
6257d0c9138Shenning 	if (r->ifname[0]) {
6267d0c9138Shenning 		if (r->ifnot)
6277d0c9138Shenning 			printf(" on ! %s", r->ifname);
6287d0c9138Shenning 		else
62914a9b182Skjell 			printf(" on %s", r->ifname);
6307d0c9138Shenning 	}
631cb3a4e31Sjasoni 	if (r->rt) {
632cb3a4e31Sjasoni 		if (r->rt == PF_ROUTETO)
633cb3a4e31Sjasoni 			printf(" route-to");
634fa1cdd09Sdhartmei 		else if (r->rt == PF_REPLYTO)
635fa1cdd09Sdhartmei 			printf(" reply-to");
636cb3a4e31Sjasoni 		else if (r->rt == PF_DUPTO)
637cb3a4e31Sjasoni 			printf(" dup-to");
638cb3a4e31Sjasoni 		else if (r->rt == PF_FASTROUTE)
639cb3a4e31Sjasoni 			printf(" fastroute");
640790504a6Sdhartmei 		if (r->rt != PF_FASTROUTE) {
641790504a6Sdhartmei 			printf(" ");
6421df6a140Scedric 			print_pool(&r->rpool, 0, 0, r->af, PF_PASS);
643790504a6Sdhartmei 		}
644cb3a4e31Sjasoni 	}
64530620b12Sfrantzen 	if (r->af) {
64630620b12Sfrantzen 		if (r->af == AF_INET)
64730620b12Sfrantzen 			printf(" inet");
64830620b12Sfrantzen 		else
64930620b12Sfrantzen 			printf(" inet6");
65030620b12Sfrantzen 	}
65114a9b182Skjell 	if (r->proto) {
652e4ebe044Shenning 		struct protoent	*p;
653ed99c291Sderaadt 
654e4ebe044Shenning 		if ((p = getprotobynumber(r->proto)) != NULL)
65514a9b182Skjell 			printf(" proto %s", p->p_name);
65614a9b182Skjell 		else
65714a9b182Skjell 			printf(" proto %u", r->proto);
65814a9b182Skjell 	}
659*64b4b616Sfrantzen 	print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto,
660*64b4b616Sfrantzen 	    verbose);
661c16ab608Sdhartmei 	if (r->uid.op)
6621173271aScedric 		print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
6631173271aScedric 		    UID_MAX);
664c16ab608Sdhartmei 	if (r->gid.op)
6651173271aScedric 		print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
6661173271aScedric 		    GID_MAX);
66714a9b182Skjell 	if (r->flags || r->flagset) {
66814a9b182Skjell 		printf(" flags ");
66914a9b182Skjell 		print_flags(r->flags);
67014a9b182Skjell 		printf("/");
67114a9b182Skjell 		print_flags(r->flagset);
67214a9b182Skjell 	}
673082ebc44Swilfried 	if (r->type) {
674b49ca6bbShenning 		const struct icmptypeent	*it;
675082ebc44Swilfried 
676b49ca6bbShenning 		it = geticmptypebynumber(r->type-1, r->af);
677d14c53d7Swilfried 		if (r->af != AF_INET6)
678d14c53d7Swilfried 			printf(" icmp-type");
679082ebc44Swilfried 		else
680d0cb3502Smcbride 			printf(" icmp6-type");
681b49ca6bbShenning 		if (it != NULL)
682b49ca6bbShenning 			printf(" %s", it->name);
683d14c53d7Swilfried 		else
684d14c53d7Swilfried 			printf(" %u", r->type-1);
685082ebc44Swilfried 		if (r->code) {
686b49ca6bbShenning 			const struct icmpcodeent	*ic;
687082ebc44Swilfried 
688b49ca6bbShenning 			ic = geticmpcodebynumber(r->type-1, r->code-1, r->af);
689b49ca6bbShenning 			if (ic != NULL)
690b49ca6bbShenning 				printf(" code %s", ic->name);
691082ebc44Swilfried 			else
69214a9b182Skjell 				printf(" code %u", r->code-1);
693082ebc44Swilfried 		}
694082ebc44Swilfried 	}
695e4cbe364Sdhartmei 	if (r->tos)
696e4cbe364Sdhartmei 		printf(" tos 0x%2.2x", r->tos);
697b96c47abSfrantzen 	if (r->keep_state == PF_STATE_NORMAL)
69814a9b182Skjell 		printf(" keep state");
699b96c47abSfrantzen 	else if (r->keep_state == PF_STATE_MODULATE)
700b96c47abSfrantzen 		printf(" modulate state");
70152e0438eSdhartmei 	else if (r->keep_state == PF_STATE_SYNPROXY)
70252e0438eSdhartmei 		printf(" synproxy state");
703cc5f0329Sdhartmei 	opts = 0;
704b3c86969Sdhartmei 	if (r->max_states)
705cc5f0329Sdhartmei 		opts = 1;
706cc5f0329Sdhartmei 	for (i = 0; !opts && i < PFTM_MAX; ++i)
707cc5f0329Sdhartmei 		if (r->timeout[i])
708cc5f0329Sdhartmei 			opts = 1;
709cc5f0329Sdhartmei 	if (opts) {
710cc5f0329Sdhartmei 		printf(" (");
711cc5f0329Sdhartmei 		if (r->max_states) {
712cc5f0329Sdhartmei 			printf("max %u", r->max_states);
713cc5f0329Sdhartmei 			opts = 0;
714cc5f0329Sdhartmei 		}
715cc5f0329Sdhartmei 		for (i = 0; i < PFTM_MAX; ++i)
716cc5f0329Sdhartmei 			if (r->timeout[i]) {
717cc5f0329Sdhartmei 				if (!opts)
718cc5f0329Sdhartmei 					printf(", ");
719cc5f0329Sdhartmei 				opts = 0;
720cc5f0329Sdhartmei 				printf("%s %u", pf_timeouts[i].name,
721cc5f0329Sdhartmei 				    r->timeout[i]);
722cc5f0329Sdhartmei 			}
723cc5f0329Sdhartmei 		printf(")");
724cc5f0329Sdhartmei 	}
7256673dee2Sdhartmei 	if (r->rule_flag & PFRULE_FRAGMENT)
7266673dee2Sdhartmei 		printf(" fragment");
72767d2a440Sprovos 	if (r->rule_flag & PFRULE_NODF)
72867d2a440Sprovos 		printf(" no-df");
729edbe3066Sdhartmei 	if (r->rule_flag & PFRULE_RANDOMID)
730edbe3066Sdhartmei 		printf(" random-id");
731e258bfd4Sprovos 	if (r->min_ttl)
73234c76dcbSprovos 		printf(" min-ttl %d", r->min_ttl);
733cfa91859Sjasoni 	if (r->max_mss)
734cfa91859Sjasoni 		printf(" max-mss %d", r->max_mss);
735f48d62b3Sdhartmei 	if (r->allow_opts)
736f48d62b3Sdhartmei 		printf(" allow-opts");
737b02af636Sfrantzen 	if (r->action == PF_SCRUB) {
7382b95ca55Sfrantzen 		if (r->rule_flag & PFRULE_REASSEMBLE_TCP)
7392b95ca55Sfrantzen 			printf(" reassemble tcp");
7402b95ca55Sfrantzen 
741b02af636Sfrantzen 		if (r->rule_flag & PFRULE_FRAGDROP)
742b02af636Sfrantzen 			printf(" fragment drop-ovl");
743b02af636Sfrantzen 		else if (r->rule_flag & PFRULE_FRAGCROP)
744b02af636Sfrantzen 			printf(" fragment crop");
745b02af636Sfrantzen 		else
746b02af636Sfrantzen 			printf(" fragment reassemble");
747b02af636Sfrantzen 	}
748455ef0c1Sdhartmei 	if (r->label[0])
749ff45dfa8Scamield 		printf(" label \"%s\"", r->label);
750f98324c6Shenning 	if (r->qname[0] && r->pqname[0])
751f98324c6Shenning 		printf(" queue(%s, %s)", r->qname, r->pqname);
752f98324c6Shenning 	else if (r->qname[0])
75378e1d2a6Shenning 		printf(" queue %s", r->qname);
7548aecb81aShenning 	if (r->tagname[0])
7558aecb81aShenning 		printf(" tag %s", r->tagname);
75636369899Shenning 	if (r->match_tagname[0]) {
75736369899Shenning 		if (r->match_tag_not)
75836369899Shenning 			printf(" !");
7590a5f7f2fShenning 		printf(" tagged %s", r->match_tagname);
76036369899Shenning 	}
761d0aca2f2Shenning 	if (!r->anchorname[0] && (r->action == PF_NAT ||
762d0aca2f2Shenning 	    r->action == PF_BINAT || r->action == PF_RDR)) {
763d0aca2f2Shenning 		printf(" -> ");
764d0aca2f2Shenning 		print_pool(&r->rpool, r->rpool.proxy_port[0],
765d0aca2f2Shenning 		    r->rpool.proxy_port[1], r->af, r->action);
766d0aca2f2Shenning 	}
76714a9b182Skjell 	printf("\n");
76814a9b182Skjell }
76914a9b182Skjell 
7705b6c447dScedric void
7715b6c447dScedric print_tabledef(const char *name, int flags, int addrs,
7725b6c447dScedric     struct node_tinithead *nodes)
7735b6c447dScedric {
7745b6c447dScedric 	struct node_tinit	*ti, *nti;
7755b6c447dScedric 	struct node_host	*h;
7765b6c447dScedric 
7775b6c447dScedric 	printf("table <%s>", name);
7785b6c447dScedric 	if (flags & PFR_TFLAG_CONST)
7795b6c447dScedric 		printf(" const");
7805b6c447dScedric 	if (flags & PFR_TFLAG_PERSIST)
7815b6c447dScedric 		printf(" persist");
7825b6c447dScedric 	SIMPLEQ_FOREACH(ti, nodes, entries) {
7835b6c447dScedric 		if (ti->file) {
7845b6c447dScedric 			printf(" file \"%s\"", ti->file);
7855b6c447dScedric 			continue;
7865b6c447dScedric 		}
7875b6c447dScedric 		printf(" {");
7885b6c447dScedric 		for (;;) {
7895b6c447dScedric 			for (h = ti->host; h != NULL; h = h->next) {
7905b6c447dScedric 				printf(h->not ? " !" : " ");
7915b6c447dScedric 				print_addr(&h->addr, h->af, 0);
7925b6c447dScedric 			}
7935b6c447dScedric 			nti = SIMPLEQ_NEXT(ti, entries);
7945b6c447dScedric 			if (nti != NULL && nti->file == NULL)
7955b6c447dScedric 				ti = nti;	/* merge lists */
7965b6c447dScedric 			else
7975b6c447dScedric 				break;
7985b6c447dScedric 		}
7995b6c447dScedric 		printf(" }");
8005b6c447dScedric 	}
8015b6c447dScedric 	if (addrs && SIMPLEQ_EMPTY(nodes))
8025b6c447dScedric 		printf(" { }");
8035b6c447dScedric 	printf("\n");
8045b6c447dScedric }
8055b6c447dScedric 
8061f8f21bdSmillert int
807ff352a37Smarkus parse_flags(char *s)
80814a9b182Skjell {
809ff352a37Smarkus 	char		*p, *q;
81014a9b182Skjell 	u_int8_t	 f = 0;
81181a15e5dSderaadt 
812ff352a37Smarkus 	for (p = s; *p; p++) {
813ff352a37Smarkus 		if ((q = strchr(tcpflags, *p)) == NULL)
814ff352a37Smarkus 			return -1;
815ff352a37Smarkus 		else
816ff352a37Smarkus 			f |= 1 << (q - tcpflags);
81714a9b182Skjell 	}
818bc795af0Shugh 	return (f ? f : PF_TH_ALL);
81914a9b182Skjell }
82094e9410bShenning 
82194e9410bShenning void
82294e9410bShenning set_ipmask(struct node_host *h, u_int8_t b)
82394e9410bShenning {
82494e9410bShenning 	struct pf_addr	*m, *n;
82594e9410bShenning 	int		 i, j = 0;
82694e9410bShenning 
82794e9410bShenning 	m = &h->addr.v.a.mask;
82894e9410bShenning 
82994e9410bShenning 	for (i = 0; i < 4; i++)
83094e9410bShenning 		m->addr32[i] = 0;
83194e9410bShenning 
83294e9410bShenning 	while (b >= 32) {
83394e9410bShenning 		m->addr32[j++] = 0xffffffff;
83494e9410bShenning 		b -= 32;
83594e9410bShenning 	}
83694e9410bShenning 	for (i = 31; i > 31-b; --i)
83794e9410bShenning 		m->addr32[j] |= (1 << i);
83894e9410bShenning 	if (b)
83994e9410bShenning 		m->addr32[j] = htonl(m->addr32[j]);
84094e9410bShenning 
84194e9410bShenning 	/* Mask off bits of the address that will never be used. */
84294e9410bShenning 	n = &h->addr.v.a.addr;
843ff626af1Shenning 	if (h->addr.type == PF_ADDR_ADDRMASK)
84494e9410bShenning 		for (i = 0; i < 4; i++)
84594e9410bShenning 			n->addr32[i] = n->addr32[i] & m->addr32[i];
84694e9410bShenning }
84794e9410bShenning 
84852f4a4a4Shenning int
84952f4a4a4Shenning check_netmask(struct node_host *h, sa_family_t af)
85052f4a4a4Shenning {
85152f4a4a4Shenning 	struct node_host	*n = NULL;
85252f4a4a4Shenning 	struct pf_addr	*m;
85352f4a4a4Shenning 
85452f4a4a4Shenning 	for (n = h; n != NULL; n = n->next) {
85552f4a4a4Shenning 		m = &h->addr.v.a.mask;
85652f4a4a4Shenning 		/* fix up netmask for dynaddr */
85752f4a4a4Shenning 		if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL &&
85852f4a4a4Shenning 		    unmask(m, AF_INET6) > 32)
85952f4a4a4Shenning 			set_ipmask(n, 32);
86052f4a4a4Shenning 		/* netmasks > 32 bit are invalid on v4 */
86152f4a4a4Shenning 		if (af == AF_INET &&
86252f4a4a4Shenning 		    (m->addr32[1] || m->addr32[2] || m->addr32[3])) {
86352f4a4a4Shenning 			fprintf(stderr, "netmask %u invalid for IPv4 address\n",
86452f4a4a4Shenning 			    unmask(m, AF_INET6));
86552f4a4a4Shenning 			return (1);
86652f4a4a4Shenning 		}
86752f4a4a4Shenning 	}
86852f4a4a4Shenning 	return (0);
86952f4a4a4Shenning }
87052f4a4a4Shenning 
87194e9410bShenning /* interface lookup routines */
87294e9410bShenning 
87394e9410bShenning struct node_host	*iftab;
87494e9410bShenning 
87594e9410bShenning void
87694e9410bShenning ifa_load(void)
87794e9410bShenning {
87894e9410bShenning 	struct ifaddrs		*ifap, *ifa;
87994e9410bShenning 	struct node_host	*n = NULL, *h = NULL;
88094e9410bShenning 
88194e9410bShenning 	if (getifaddrs(&ifap) < 0)
88294e9410bShenning 		err(1, "getifaddrs");
88394e9410bShenning 
88494e9410bShenning 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
88594e9410bShenning 		if (!(ifa->ifa_addr->sa_family == AF_INET ||
88694e9410bShenning 		    ifa->ifa_addr->sa_family == AF_INET6 ||
88794e9410bShenning 		    ifa->ifa_addr->sa_family == AF_LINK))
88894e9410bShenning 				continue;
88994e9410bShenning 		n = calloc(1, sizeof(struct node_host));
89094e9410bShenning 		if (n == NULL)
89194e9410bShenning 			err(1, "address: calloc");
89294e9410bShenning 		n->af = ifa->ifa_addr->sa_family;
89394e9410bShenning 		n->ifa_flags = ifa->ifa_flags;
89494e9410bShenning #ifdef __KAME__
89594e9410bShenning 		if (n->af == AF_INET6 &&
89694e9410bShenning 		    IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)
89794e9410bShenning 		    ifa->ifa_addr)->sin6_addr) &&
89894e9410bShenning 		    ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) {
89994e9410bShenning 			struct sockaddr_in6	*sin6;
90094e9410bShenning 
90194e9410bShenning 			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
90294e9410bShenning 			sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
90394e9410bShenning 			    sin6->sin6_addr.s6_addr[3];
90494e9410bShenning 			sin6->sin6_addr.s6_addr[2] = 0;
90594e9410bShenning 			sin6->sin6_addr.s6_addr[3] = 0;
90694e9410bShenning 		}
90794e9410bShenning #endif
90894e9410bShenning 		n->ifindex = 0;
90994e9410bShenning 		if (n->af == AF_INET) {
91094e9410bShenning 			memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *)
91194e9410bShenning 			    ifa->ifa_addr)->sin_addr.s_addr,
91294e9410bShenning 			    sizeof(struct in_addr));
91394e9410bShenning 			memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *)
91494e9410bShenning 			    ifa->ifa_netmask)->sin_addr.s_addr,
91594e9410bShenning 			    sizeof(struct in_addr));
91694e9410bShenning 			if (ifa->ifa_broadaddr != NULL)
91794e9410bShenning 				memcpy(&n->bcast, &((struct sockaddr_in *)
91894e9410bShenning 				    ifa->ifa_broadaddr)->sin_addr.s_addr,
91994e9410bShenning 				    sizeof(struct in_addr));
92094e9410bShenning 		} else if (n->af == AF_INET6) {
92194e9410bShenning 			memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *)
92294e9410bShenning 			    ifa->ifa_addr)->sin6_addr.s6_addr,
92394e9410bShenning 			    sizeof(struct in6_addr));
92494e9410bShenning 			memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *)
92594e9410bShenning 			    ifa->ifa_netmask)->sin6_addr.s6_addr,
92694e9410bShenning 			    sizeof(struct in6_addr));
92794e9410bShenning 			if (ifa->ifa_broadaddr != NULL)
92894e9410bShenning 				memcpy(&n->bcast, &((struct sockaddr_in6 *)
92994e9410bShenning 				    ifa->ifa_broadaddr)->sin6_addr.s6_addr,
93094e9410bShenning 				    sizeof(struct in6_addr));
93194e9410bShenning 			n->ifindex = ((struct sockaddr_in6 *)
93294e9410bShenning 			    ifa->ifa_addr)->sin6_scope_id;
93394e9410bShenning 		}
93494e9410bShenning 		if ((n->ifname = strdup(ifa->ifa_name)) == NULL)
93594e9410bShenning 			err(1, "ifa_load: strdup");
93694e9410bShenning 		n->next = NULL;
93794e9410bShenning 		n->tail = n;
93894e9410bShenning 		if (h == NULL)
93994e9410bShenning 			h = n;
94094e9410bShenning 		else {
94194e9410bShenning 			h->tail->next = n;
94294e9410bShenning 			h->tail = n;
94394e9410bShenning 		}
94494e9410bShenning 	}
94594e9410bShenning 	iftab = h;
94694e9410bShenning 	freeifaddrs(ifap);
94794e9410bShenning }
94894e9410bShenning 
94994e9410bShenning struct node_host *
9506cba701cShenning ifa_exists(const char *ifa_name)
95194e9410bShenning {
95294e9410bShenning 	struct node_host	*n;
95394e9410bShenning 
95494e9410bShenning 	if (iftab == NULL)
95594e9410bShenning 		ifa_load();
95694e9410bShenning 
95794e9410bShenning 	for (n = iftab; n; n = n->next) {
95894e9410bShenning 		if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
95994e9410bShenning 			return (n);
96094e9410bShenning 	}
96194e9410bShenning 	return (NULL);
96294e9410bShenning }
96394e9410bShenning 
96494e9410bShenning struct node_host *
9656cba701cShenning ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode)
96694e9410bShenning {
96794e9410bShenning 	struct node_host	*p = NULL, *h = NULL, *n = NULL;
96894e9410bShenning 	int			 return_all = 0;
96994e9410bShenning 
97094e9410bShenning 	if (!strncmp(ifa_name, "self", IFNAMSIZ))
97194e9410bShenning 		return_all = 1;
97294e9410bShenning 
97394e9410bShenning 	if (iftab == NULL)
97494e9410bShenning 		ifa_load();
97594e9410bShenning 
97694e9410bShenning 	for (p = iftab; p; p = p->next) {
97794e9410bShenning 		if (!((p->af == AF_INET || p->af == AF_INET6) &&
97894e9410bShenning 		    (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all)))
97994e9410bShenning 			continue;
98094e9410bShenning 		if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
98194e9410bShenning 			continue;
98294e9410bShenning 		if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
98394e9410bShenning 			continue;
98494e9410bShenning 		n = calloc(1, sizeof(struct node_host));
98594e9410bShenning 		if (n == NULL)
98694e9410bShenning 			err(1, "address: calloc");
98794e9410bShenning 		n->af = p->af;
98894e9410bShenning 		if (mode == PFCTL_IFLOOKUP_BCAST)
98994e9410bShenning 			memcpy(&n->addr.v.a.addr, &p->bcast,
99094e9410bShenning 			    sizeof(struct pf_addr));
99194e9410bShenning 		else
99294e9410bShenning 			memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr,
99394e9410bShenning 			    sizeof(struct pf_addr));
99494e9410bShenning 		if (mode == PFCTL_IFLOOKUP_NET)
99594e9410bShenning 			set_ipmask(n, unmask(&p->addr.v.a.mask, n->af));
99694e9410bShenning 		else {
99794e9410bShenning 			if (n->af == AF_INET) {
99894e9410bShenning 				if (p->ifa_flags & IFF_LOOPBACK &&
99994e9410bShenning 				    p->ifa_flags & IFF_LINK1)
100094e9410bShenning 					memcpy(&n->addr.v.a.mask,
100194e9410bShenning 					    &p->addr.v.a.mask,
100294e9410bShenning 					    sizeof(struct pf_addr));
100394e9410bShenning 				else
100494e9410bShenning 					set_ipmask(n, 32);
100594e9410bShenning 			} else
100694e9410bShenning 				set_ipmask(n, 128);
100794e9410bShenning 		}
100894e9410bShenning 		n->ifindex = p->ifindex;
100994e9410bShenning 
101094e9410bShenning 		n->next = NULL;
101194e9410bShenning 		n->tail = n;
101294e9410bShenning 		if (h == NULL)
101394e9410bShenning 			h = n;
101494e9410bShenning 		else {
101594e9410bShenning 			h->tail->next = n;
101694e9410bShenning 			h->tail = n;
101794e9410bShenning 		}
101894e9410bShenning 	}
101994e9410bShenning 	if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) {
102094e9410bShenning 		fprintf(stderr, "no IP address found for %s\n", ifa_name);
102194e9410bShenning 	}
102294e9410bShenning 	return (h);
102394e9410bShenning }
102494e9410bShenning 
102594e9410bShenning struct node_host *
1026f23861c1Shenning host(const char *s)
102794e9410bShenning {
10282a6c1abaShenning 	struct node_host	*h = NULL;
1029f23861c1Shenning 	int			 mask, v4mask, v6mask, cont = 1;
1030f23861c1Shenning 	char			*p, *q, *ps;
103194e9410bShenning 
103294e9410bShenning 	if ((p = strrchr(s, '/')) != NULL) {
103394e9410bShenning 		mask = strtol(p+1, &q, 0);
1034fecc9cd0Shenning 		if (!q || *q || mask > 128 || q == (p+1)) {
103594e9410bShenning 			fprintf(stderr, "invalid netmask\n");
103694e9410bShenning 			return (NULL);
103794e9410bShenning 		}
1038a81c851cShenning 		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
103994e9410bShenning 			err(1, "host: malloc");
104094e9410bShenning 		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
104194e9410bShenning 		v4mask = v6mask = mask;
104294e9410bShenning 	} else {
1043f23861c1Shenning 		if ((ps = strdup(s)) == NULL)
1044f23861c1Shenning 			err(1, "host: strdup");
104594e9410bShenning 		v4mask = 32;
104694e9410bShenning 		v6mask = 128;
1047f23861c1Shenning 		mask = -1;
104894e9410bShenning 	}
104994e9410bShenning 
10502a6c1abaShenning 	/* interface with this name exists? */
10514a36d485Shenning 	if (cont && (h = host_if(ps, mask)) != NULL)
10522a6c1abaShenning 		cont = 0;
10532a6c1abaShenning 
10542a6c1abaShenning 	/* IPv4 address? */
1055f23861c1Shenning 	if (cont && (h = host_v4(s, mask)) != NULL)
10562a6c1abaShenning 		cont = 0;
10572a6c1abaShenning 
10582a6c1abaShenning 	/* IPv6 address? */
10592a6c1abaShenning 	if (cont && (h = host_v6(ps, v6mask)) != NULL)
10602a6c1abaShenning 		cont = 0;
10612a6c1abaShenning 
10622a6c1abaShenning 	/* dns lookup */
10632a6c1abaShenning 	if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL)
10642a6c1abaShenning 		cont = 0;
10652a6c1abaShenning 	free(ps);
10662a6c1abaShenning 
10672a6c1abaShenning 	if (h == NULL || cont == 1) {
10682a6c1abaShenning 		fprintf(stderr, "no IP address found for %s\n", s);
10692a6c1abaShenning 		return (NULL);
10702a6c1abaShenning 	}
10712a6c1abaShenning 	return (h);
10722a6c1abaShenning }
10732a6c1abaShenning 
10742a6c1abaShenning struct node_host *
1075f2370d27Shenning host_if(const char *s, int mask)
10762a6c1abaShenning {
10772a6c1abaShenning 	struct node_host	*n, *h = NULL;
10784a36d485Shenning 	char			*p, *ps;
10794a36d485Shenning 	int			 mode = PFCTL_IFLOOKUP_HOST;
10802a6c1abaShenning 
10814a36d485Shenning 	if ((p = strrchr(s, ':')) != NULL &&
10824a36d485Shenning 	    (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) {
10834a36d485Shenning 		if (!strcmp(p+1, "network"))
10844a36d485Shenning 			mode = PFCTL_IFLOOKUP_NET;
10854a36d485Shenning 		if (!strcmp(p+1, "broadcast"))
10864a36d485Shenning 			mode = PFCTL_IFLOOKUP_BCAST;
10874a36d485Shenning 		if (mask > -1) {
10884a36d485Shenning 			fprintf(stderr, "network or broadcast lookup, but "
10894a36d485Shenning 			    "extra netmask given\n");
10904a36d485Shenning 			return (NULL);
10914a36d485Shenning 		}
10924a36d485Shenning 		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
10934a36d485Shenning 			err(1, "host: malloc");
10944a36d485Shenning 		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
10954a36d485Shenning 	} else
10964a36d485Shenning 		if ((ps = strdup(s)) == NULL)
10974a36d485Shenning 			err(1, "host_if: strdup");
10984a36d485Shenning 
10994a36d485Shenning 	if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
11002a6c1abaShenning 		/* interface with this name exists */
11014a36d485Shenning 		h = ifa_lookup(ps, mode);
11022a6c1abaShenning 		for (n = h; n != NULL && mask > -1; n = n->next)
11032a6c1abaShenning 			set_ipmask(n, mask);
11042a6c1abaShenning 	}
11054a36d485Shenning 
11064a36d485Shenning 	free(ps);
11072a6c1abaShenning 	return (h);
11082a6c1abaShenning }
11092a6c1abaShenning 
11102a6c1abaShenning struct node_host *
1111383ebbbfShenning host_v4(const char *s, int mask)
11122a6c1abaShenning {
11132a6c1abaShenning 	struct node_host	*h = NULL;
11142a6c1abaShenning 	struct in_addr		 ina;
11152a6c1abaShenning 	int			 bits;
11162a6c1abaShenning 
111794e9410bShenning 	memset(&ina, 0, sizeof(struct in_addr));
11183c58a40aScedric 	if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) > -1) {
111994e9410bShenning 		h = calloc(1, sizeof(struct node_host));
112094e9410bShenning 		if (h == NULL)
112194e9410bShenning 			err(1, "address: calloc");
112294e9410bShenning 		h->ifname = NULL;
112394e9410bShenning 		h->af = AF_INET;
112494e9410bShenning 		h->addr.v.a.addr.addr32[0] = ina.s_addr;
112594e9410bShenning 		set_ipmask(h, bits);
112694e9410bShenning 		h->next = NULL;
112794e9410bShenning 		h->tail = h;
112894e9410bShenning 	}
11292a6c1abaShenning 
113094e9410bShenning 	return (h);
113194e9410bShenning }
11322a6c1abaShenning 
11332a6c1abaShenning struct node_host *
1134f2370d27Shenning host_v6(const char *s, int mask)
11352a6c1abaShenning {
11362a6c1abaShenning 	struct addrinfo		 hints, *res;
11372a6c1abaShenning 	struct node_host	*h = NULL;
113894e9410bShenning 
113994e9410bShenning 	memset(&hints, 0, sizeof(hints));
114094e9410bShenning 	hints.ai_family = AF_INET6;
114194e9410bShenning 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
114294e9410bShenning 	hints.ai_flags = AI_NUMERICHOST;
11432a6c1abaShenning 	if (getaddrinfo(s, "0", &hints, &res) == 0) {
11442a6c1abaShenning 		h = calloc(1, sizeof(struct node_host));
11452a6c1abaShenning 		if (h == NULL)
114694e9410bShenning 			err(1, "address: calloc");
11472a6c1abaShenning 		h->ifname = NULL;
11482a6c1abaShenning 		h->af = AF_INET6;
11492a6c1abaShenning 		memcpy(&h->addr.v.a.addr,
115094e9410bShenning 		    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
11512a6c1abaShenning 		    sizeof(h->addr.v.a.addr));
11522a6c1abaShenning 		h->ifindex =
11532a6c1abaShenning 		    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
11542a6c1abaShenning 		set_ipmask(h, mask);
115594e9410bShenning 		freeaddrinfo(res);
11562a6c1abaShenning 		h->next = NULL;
11572a6c1abaShenning 		h->tail = h;
115894e9410bShenning 	}
115994e9410bShenning 
11602a6c1abaShenning 	return (h);
11612a6c1abaShenning }
11622a6c1abaShenning 
11632a6c1abaShenning struct node_host *
1164f2370d27Shenning host_dns(const char *s, int v4mask, int v6mask)
11652a6c1abaShenning {
11662a6c1abaShenning 	struct addrinfo		 hints, *res0, *res;
11672a6c1abaShenning 	struct node_host	*n, *h = NULL;
11682a6c1abaShenning 	int			 error;
11692a6c1abaShenning 
117094e9410bShenning 	memset(&hints, 0, sizeof(hints));
117194e9410bShenning 	hints.ai_family = PF_UNSPEC;
117294e9410bShenning 	hints.ai_socktype = SOCK_STREAM; /* DUMMY */
11732a6c1abaShenning 	error = getaddrinfo(s, NULL, &hints, &res0);
11742a6c1abaShenning 	if (error)
11752a6c1abaShenning 		return (h);
11762a6c1abaShenning 
117794e9410bShenning 	for (res = res0; res; res = res->ai_next) {
117894e9410bShenning 		if (res->ai_family != AF_INET &&
117994e9410bShenning 		    res->ai_family != AF_INET6)
118094e9410bShenning 			continue;
118194e9410bShenning 		n = calloc(1, sizeof(struct node_host));
118294e9410bShenning 		if (n == NULL)
11832a6c1abaShenning 			err(1, "host_dns: calloc");
118494e9410bShenning 		n->ifname = NULL;
118594e9410bShenning 		n->af = res->ai_family;
118694e9410bShenning 		if (res->ai_family == AF_INET) {
118794e9410bShenning 			memcpy(&n->addr.v.a.addr,
11882a6c1abaShenning 			    &((struct sockaddr_in *)
11892a6c1abaShenning 			    res->ai_addr)->sin_addr.s_addr,
119094e9410bShenning 			    sizeof(struct in_addr));
119194e9410bShenning 			set_ipmask(n, v4mask);
119294e9410bShenning 		} else {
119394e9410bShenning 			memcpy(&n->addr.v.a.addr,
11942a6c1abaShenning 			    &((struct sockaddr_in6 *)
11952a6c1abaShenning 			    res->ai_addr)->sin6_addr.s6_addr,
119694e9410bShenning 			    sizeof(struct in6_addr));
119794e9410bShenning 			n->ifindex =
11982a6c1abaShenning 			    ((struct sockaddr_in6 *)
11992a6c1abaShenning 			    res->ai_addr)->sin6_scope_id;
120094e9410bShenning 			set_ipmask(n, v6mask);
120194e9410bShenning 		}
120294e9410bShenning 		n->next = NULL;
120394e9410bShenning 		n->tail = n;
120494e9410bShenning 		if (h == NULL)
120594e9410bShenning 			h = n;
120694e9410bShenning 		else {
120794e9410bShenning 			h->tail->next = n;
120894e9410bShenning 			h->tail = n;
120994e9410bShenning 		}
121094e9410bShenning 	}
121194e9410bShenning 	freeaddrinfo(res0);
121294e9410bShenning 
121394e9410bShenning 	return (h);
121494e9410bShenning }
121542e05679Scedric 
121642e05679Scedric /*
121742e05679Scedric  * convert a hostname to a list of addresses and put them in the given buffer.
121842e05679Scedric  * test:
121942e05679Scedric  *	if set to 1, only simple addresses are accepted (no netblock, no "!").
122042e05679Scedric  */
122142e05679Scedric int
122242e05679Scedric append_addr(struct pfr_buffer *b, char *s, int test)
122342e05679Scedric {
12245b6c447dScedric 	char			 *r;
1225b88a8d5dScedric 	struct node_host	*h, *n;
1226b88a8d5dScedric 	int			 rv, not = 0;
12275b6c447dScedric 
12285b6c447dScedric 	for (r = s; *r == '!'; r++)
12295b6c447dScedric 		not = !not;
12305b6c447dScedric 	if ((n = host(r)) == NULL) {
12315b6c447dScedric 		errno = 0;
12325b6c447dScedric 		return (-1);
12335b6c447dScedric 	}
1234b88a8d5dScedric 	rv = append_addr_host(b, n, test, not);
1235b88a8d5dScedric 	do {
1236b88a8d5dScedric 		h = n;
1237b88a8d5dScedric 		n = n->next;
1238b88a8d5dScedric 		free(h);
1239b88a8d5dScedric 	} while (n != NULL);
1240b88a8d5dScedric 	return (rv);
124142e05679Scedric }
124242e05679Scedric 
124342e05679Scedric /*
12445b6c447dScedric  * same as previous function, but with a pre-parsed input and the ability
1245b88a8d5dScedric  * to "negate" the result. Does not free the node_host list.
124642e05679Scedric  * not:
124742e05679Scedric  *      setting it to 1 is equivalent to adding "!" in front of parameter s.
124842e05679Scedric  */
124942e05679Scedric int
12505b6c447dScedric append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not)
125142e05679Scedric {
125242e05679Scedric 	int			 bits;
125342e05679Scedric 	struct pfr_addr		 addr;
125442e05679Scedric 
125542e05679Scedric 	do {
125642e05679Scedric 		bzero(&addr, sizeof(addr));
12575b6c447dScedric 		addr.pfra_not = n->not ^ not;
125842e05679Scedric 		addr.pfra_af = n->af;
125942e05679Scedric 		addr.pfra_net = unmask(&n->addr.v.a.mask, n->af);
126042e05679Scedric 		switch (n->af) {
126142e05679Scedric 		case AF_INET:
126242e05679Scedric 			addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0];
126342e05679Scedric 			bits = 32;
126442e05679Scedric 			break;
126542e05679Scedric 		case AF_INET6:
126642e05679Scedric 			memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6,
126742e05679Scedric 			    sizeof(struct in6_addr));
126842e05679Scedric 			bits = 128;
126942e05679Scedric 			break;
127042e05679Scedric 		default:
127142e05679Scedric 			errno = EINVAL;
127242e05679Scedric 			return (-1);
127342e05679Scedric 		}
127442e05679Scedric 		if ((test && (not || addr.pfra_net != bits)) ||
127542e05679Scedric 		    addr.pfra_net > bits) {
127642e05679Scedric 			errno = EINVAL;
127742e05679Scedric 			return (-1);
127842e05679Scedric 		}
127942e05679Scedric 		if (pfr_buf_add(b, &addr))
128042e05679Scedric 			return (-1);
1281b88a8d5dScedric 	} while ((n = n->next) != NULL);
128242e05679Scedric 
128342e05679Scedric 	return (0);
128442e05679Scedric }
1285