xref: /openbsd/sbin/pfctl/pfctl_parser.c (revision d0aca2f2)
1*d0aca2f2Shenning /*	$OpenBSD: pfctl_parser.c,v 1.155 2003/05/14 00:56:38 henning 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);
6115e76891Sdhartmei void		 print_fromto(struct pf_rule_addr *, struct pf_rule_addr *,
6244f5ed0aScedric 		    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 },
10730620b12Sfrantzen 	{ "listqry",	MLD6_LISTENER_QUERY },
10830620b12Sfrantzen 	{ "grouprep",	ICMP6_MEMBERSHIP_REPORT },
10930620b12Sfrantzen 	{ "listenrep",	MLD6_LISTENER_REPORT },
11030620b12Sfrantzen 	{ "groupterm",	ICMP6_MEMBERSHIP_REDUCTION },
11130620b12Sfrantzen 	{ "listendone", MLD6_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 },
12430620b12Sfrantzen 	{ "mtraceresp",	MLD6_MTRACE_RESP },
12530620b12Sfrantzen 	{ "mtrace",	MLD6_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
35215e76891Sdhartmei print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst,
35344f5ed0aScedric     sa_family_t af, u_int8_t proto, int verbose)
35415e76891Sdhartmei {
3551173271aScedric 	if (src->addr.type == PF_ADDR_ADDRMASK &&
3561173271aScedric 	    dst->addr.type == PF_ADDR_ADDRMASK &&
357bcf142a4Sdhartmei 	    PF_AZERO(&src->addr.v.a.addr, AF_INET6) &&
358bcf142a4Sdhartmei 	    PF_AZERO(&src->addr.v.a.mask, AF_INET6) &&
3591173271aScedric 	    PF_AZERO(&dst->addr.v.a.addr, AF_INET6) &&
3601173271aScedric 	    PF_AZERO(&dst->addr.v.a.mask, AF_INET6) &&
3611173271aScedric 	    !src->not && !dst->not &&
3621173271aScedric 	    !src->port_op && !dst->port_op)
36315e76891Sdhartmei 		printf("all ");
36415e76891Sdhartmei 	else {
36515e76891Sdhartmei 		printf("from ");
36615e76891Sdhartmei 		if (src->not)
36715e76891Sdhartmei 			printf("! ");
36844f5ed0aScedric 		print_addr(&src->addr, af, verbose);
36915e76891Sdhartmei 		printf(" ");
37015e76891Sdhartmei 		if (src->port_op)
37115e76891Sdhartmei 			print_port(src->port_op, src->port[0],
37215e76891Sdhartmei 			    src->port[1],
37315e76891Sdhartmei 			    proto == IPPROTO_TCP ? "tcp" : "udp");
37415e76891Sdhartmei 
37515e76891Sdhartmei 		printf("to ");
37615e76891Sdhartmei 		if (dst->not)
37715e76891Sdhartmei 			printf("! ");
37844f5ed0aScedric 		print_addr(&dst->addr, af, verbose);
37915e76891Sdhartmei 		printf(" ");
38015e76891Sdhartmei 		if (dst->port_op)
38115e76891Sdhartmei 			print_port(dst->port_op, dst->port[0],
38215e76891Sdhartmei 			    dst->port[1],
38315e76891Sdhartmei 			    proto == IPPROTO_TCP ? "tcp" : "udp");
38415e76891Sdhartmei 	}
38515e76891Sdhartmei }
38615e76891Sdhartmei 
38715e76891Sdhartmei void
388e0c302d0Smcbride print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2,
389e0c302d0Smcbride     sa_family_t af, int id)
3903a44df3cSmcbride {
3913a44df3cSmcbride 	struct pf_pooladdr	*pooladdr;
3923a44df3cSmcbride 
3936c917913Smcbride 	if ((TAILQ_FIRST(&pool->list) != NULL) &&
3946c917913Smcbride 	    TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
3953a44df3cSmcbride 		printf("{ ");
3963a44df3cSmcbride 	TAILQ_FOREACH(pooladdr, &pool->list, entries){
3973a44df3cSmcbride 		switch (id) {
398e8793aa9Smcbride 		case PF_NAT:
399e8793aa9Smcbride 		case PF_RDR:
400e8793aa9Smcbride 		case PF_BINAT:
40144f5ed0aScedric 			print_addr(&pooladdr->addr.addr, af, 0);
4023a44df3cSmcbride 			break;
403e8793aa9Smcbride 		case PF_PASS:
404bcf142a4Sdhartmei 			if (PF_AZERO(&pooladdr->addr.addr.v.a.addr, af))
4053b9b234fSmcbride 				printf("%s", pooladdr->ifname);
406790504a6Sdhartmei 			else {
4073a44df3cSmcbride 				printf("(%s ", pooladdr->ifname);
40844f5ed0aScedric 				print_addr(&pooladdr->addr.addr, af, 0);
4093a44df3cSmcbride 				printf(")");
4103b9b234fSmcbride 			}
4113a44df3cSmcbride 			break;
412e8793aa9Smcbride 		default:
413e8793aa9Smcbride 			break;
4143a44df3cSmcbride 		}
4153a44df3cSmcbride 		if (TAILQ_NEXT(pooladdr, entries) != NULL)
4163a44df3cSmcbride 			printf(", ");
4173a44df3cSmcbride 		else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
4183a44df3cSmcbride 			printf(" }");
4193a44df3cSmcbride 	}
420e0c302d0Smcbride 	switch (id) {
421e8793aa9Smcbride 	case PF_NAT:
422e0c302d0Smcbride 		if (p1 != PF_NAT_PROXY_PORT_LOW ||
423e0c302d0Smcbride 		    p2 != PF_NAT_PROXY_PORT_HIGH) {
424e0c302d0Smcbride 			if (p1 == p2)
425e0c302d0Smcbride 				printf(" port %u", p1);
426e0c302d0Smcbride 			else
427e0c302d0Smcbride 				printf(" port %u:%u", p1, p2);
428e0c302d0Smcbride 		}
429e0c302d0Smcbride 		break;
430e8793aa9Smcbride 	case PF_RDR:
431e0c302d0Smcbride 		if (p1) {
4328da4e377Smcbride 			printf(" port %u", p1);
4338da4e377Smcbride 			if (p2 && (p2 != p1))
4348da4e377Smcbride 				printf(":%u", p2);
435e0c302d0Smcbride 		}
436e0c302d0Smcbride 		break;
437e0c302d0Smcbride 	default:
438e0c302d0Smcbride 		break;
439e0c302d0Smcbride 	}
440e0c302d0Smcbride 	switch (pool->opts & PF_POOL_TYPEMASK) {
441e0c302d0Smcbride 	case PF_POOL_NONE:
442e0c302d0Smcbride 		break;
443e0c302d0Smcbride 	case PF_POOL_BITMASK:
444e0c302d0Smcbride 		printf(" bitmask");
445e0c302d0Smcbride 		break;
446e0c302d0Smcbride 	case PF_POOL_RANDOM:
447e0c302d0Smcbride 		printf(" random");
448e0c302d0Smcbride 		break;
449e0c302d0Smcbride 	case PF_POOL_SRCHASH:
4500436fa02Smcbride 		printf(" source-hash 0x%08x%08x%08x%08x",
451e0c302d0Smcbride 		    pool->key.key32[0], pool->key.key32[1],
452e0c302d0Smcbride 		    pool->key.key32[2], pool->key.key32[3]);
453e0c302d0Smcbride 		break;
454e0c302d0Smcbride 	case PF_POOL_ROUNDROBIN:
455e0c302d0Smcbride 		printf(" round-robin");
456e0c302d0Smcbride 		break;
457e0c302d0Smcbride 	}
458e0c302d0Smcbride 	if (pool->opts & PF_POOL_STATICPORT)
459e0c302d0Smcbride 		printf(" static-port");
4603a44df3cSmcbride }
4613a44df3cSmcbride 
462132c30ccShenning const char	*pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
463132c30ccShenning const char	*pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
46499a73934Sderaadt 
46514a9b182Skjell void
46681a15e5dSderaadt print_status(struct pf_status *s)
46714a9b182Skjell {
468e4ebe044Shenning 	char	statline[80];
469c474e331Shenning 	time_t	runtime;
47099a73934Sderaadt 	int	i;
47199a73934Sderaadt 
472c474e331Shenning 	runtime = time(NULL) - s->since;
473c474e331Shenning 
474d85e4ad6Sdhartmei 	if (s->running) {
475d85e4ad6Sdhartmei 		unsigned	sec, min, hrs, day = runtime;
476d85e4ad6Sdhartmei 
477d85e4ad6Sdhartmei 		sec = day % 60;
478d85e4ad6Sdhartmei 		day /= 60;
479d85e4ad6Sdhartmei 		min = day % 60;
480d85e4ad6Sdhartmei 		day /= 60;
481d85e4ad6Sdhartmei 		hrs = day % 24;
482d85e4ad6Sdhartmei 		day /= 24;
483c474e331Shenning 		snprintf(statline, sizeof(statline),
484d85e4ad6Sdhartmei 		    "Status: Enabled for %u days %.2u:%.2u:%.2u",
485d85e4ad6Sdhartmei 		    day, hrs, min, sec);
486d85e4ad6Sdhartmei 	} else
487c474e331Shenning 		snprintf(statline, sizeof(statline), "Status: Disabled");
488c97b4ee1Shenning 	printf("%-44s", statline);
489ae58c8acSdhartmei 	switch (s->debug) {
490ae58c8acSdhartmei 	case 0:
491c97b4ee1Shenning 		printf("%15s\n\n", "Debug: None");
492ae58c8acSdhartmei 		break;
493ae58c8acSdhartmei 	case 1:
494c97b4ee1Shenning 		printf("%15s\n\n", "Debug: Urgent");
495ae58c8acSdhartmei 		break;
496ae58c8acSdhartmei 	case 2:
497c97b4ee1Shenning 		printf("%15s\n\n", "Debug: Misc");
498ae58c8acSdhartmei 		break;
499ae58c8acSdhartmei 	}
500c474e331Shenning 	if (s->ifname[0] != 0) {
501c474e331Shenning 		printf("Interface Stats for %-16s %5s %16s\n",
502c474e331Shenning 		    s->ifname, "IPv4", "IPv6");
503c474e331Shenning 		printf("  %-25s %14llu %16llu\n", "Bytes In",
5047189e280Sdhartmei 		    s->bcounters[0][0], s->bcounters[1][0]);
505c474e331Shenning 		printf("  %-25s %14llu %16llu\n", "Bytes Out",
5067189e280Sdhartmei 		    s->bcounters[0][1], s->bcounters[1][1]);
507c474e331Shenning 		printf("  Packets In\n");
508c474e331Shenning 		printf("    %-23s %14llu %16llu\n", "Passed",
5097189e280Sdhartmei 		    s->pcounters[0][0][PF_PASS],
5107189e280Sdhartmei 		    s->pcounters[1][0][PF_PASS]);
511c474e331Shenning 		printf("    %-23s %14llu %16llu\n", "Blocked",
5127189e280Sdhartmei 		    s->pcounters[0][0][PF_DROP],
5137189e280Sdhartmei 		    s->pcounters[1][0][PF_DROP]);
514c474e331Shenning 		printf("  Packets Out\n");
515c474e331Shenning 		printf("    %-23s %14llu %16llu\n", "Passed",
5167189e280Sdhartmei 		    s->pcounters[0][1][PF_PASS],
5177189e280Sdhartmei 		    s->pcounters[1][1][PF_PASS]);
518c474e331Shenning 		printf("    %-23s %14llu %16llu\n\n", "Blocked",
5197189e280Sdhartmei 		    s->pcounters[0][1][PF_DROP],
5207189e280Sdhartmei 		    s->pcounters[1][1][PF_DROP]);
521c474e331Shenning 	}
522c474e331Shenning 	printf("%-27s %14s %16s\n", "State Table", "Total", "Rate");
523c474e331Shenning 	printf("  %-25s %14u %14s\n", "current entries", s->states, "");
524c474e331Shenning 	for (i = 0; i < FCNT_MAX; i++) {
525c474e331Shenning 		printf("  %-25s %14lld ", pf_fcounters[i],
52684976600Sderaadt 			    s->fcounters[i]);
527c474e331Shenning 		if (runtime > 0)
528c474e331Shenning 			printf("%14.1f/s\n",
529c474e331Shenning 			    (double)s->fcounters[i] / (double)runtime);
530c474e331Shenning 		else
531c474e331Shenning 			printf("%14s\n", "");
532c474e331Shenning 	}
53399a73934Sderaadt 	printf("Counters\n");
534c474e331Shenning 	for (i = 0; i < PFRES_MAX; i++) {
535c474e331Shenning 		printf("  %-25s %14lld ", pf_reasons[i],
53699a73934Sderaadt 		    s->counters[i]);
537c474e331Shenning 		if (runtime > 0)
538c474e331Shenning 			printf("%14.1f/s\n",
539c474e331Shenning 			    (double)s->counters[i] / (double)runtime);
540c474e331Shenning 		else
541c474e331Shenning 			printf("%14s\n", "");
542c474e331Shenning 	}
54314a9b182Skjell }
54414a9b182Skjell 
54514a9b182Skjell void
5461173271aScedric print_rule(struct pf_rule *r, int verbose)
54714a9b182Skjell {
5481173271aScedric 	static const char *actiontypes[] = { "pass", "block", "scrub", "nat",
5491173271aScedric 	    "no nat", "binat", "no binat", "rdr", "no rdr" };
5501173271aScedric 	static const char *anchortypes[] = { "anchor", "anchor", "anchor",
5511173271aScedric 	    "nat-anchor", "nat-anchor", "binat-anchor", "binat-anchor",
5521173271aScedric 	    "rdr-anchor", "rdr-anchor" };
553cc5f0329Sdhartmei 	int	i, opts;
554cc5f0329Sdhartmei 
55574dc4fddShenning 	if (verbose)
55678baf774Sdhartmei 		printf("@%d ", r->nr);
5571173271aScedric 	if (r->action > PF_NORDR)
5581173271aScedric 		printf("action(%d) ", r->action);
5591173271aScedric 	else if (r->anchorname[0])
5601173271aScedric 		printf("%s %s ", anchortypes[r->action], r->anchorname);
5611173271aScedric 	else
5621173271aScedric 		printf("%s ", actiontypes[r->action]);
5631173271aScedric 	if (r->action == PF_DROP) {
5648a87542aShenning 		if (r->rule_flag & PFRULE_RETURN)
5658a87542aShenning 			printf("return ");
5668a87542aShenning 		else if (r->rule_flag & PFRULE_RETURNRST) {
5671f77cc8aSpb 			if (!r->return_ttl)
56814a9b182Skjell 				printf("return-rst ");
5691f77cc8aSpb 			else
5701f77cc8aSpb 				printf("return-rst(ttl %d) ", r->return_ttl);
571328b2decShenning 		} else if (r->rule_flag & PFRULE_RETURNICMP) {
572328b2decShenning 			const struct icmpcodeent	*ic, *ic6;
573b996d042Sdhartmei 
574b996d042Sdhartmei 			ic = geticmpcodebynumber(r->return_icmp >> 8,
575328b2decShenning 			    r->return_icmp & 255, AF_INET);
576328b2decShenning 			ic6 = geticmpcodebynumber(r->return_icmp6 >> 8,
577328b2decShenning 			    r->return_icmp6 & 255, AF_INET6);
578d14c53d7Swilfried 
579328b2decShenning 			switch(r->af) {
580328b2decShenning 			case AF_INET:
581328b2decShenning 				printf("return-icmp");
582d14c53d7Swilfried 				if (ic == NULL)
583d14c53d7Swilfried 					printf("(%u) ", r->return_icmp & 255);
584b996d042Sdhartmei 				else
585328b2decShenning 					printf("(%s) ", ic->name);
586328b2decShenning 				break;
587328b2decShenning 			case AF_INET6:
588328b2decShenning 				printf("return-icmp6");
589328b2decShenning 				if (ic6 == NULL)
590328b2decShenning 					printf("(%u) ", r->return_icmp6 & 255);
591328b2decShenning 				else
592328b2decShenning 					printf("(%s) ", ic6->name);
593328b2decShenning 				break;
594328b2decShenning 			default:
595328b2decShenning 				printf("return-icmp");
596328b2decShenning 				if (ic == NULL)
597328b2decShenning 					printf("(%u, ", r->return_icmp & 255);
598328b2decShenning 				else
599328b2decShenning 					printf("(%s, ", ic->name);
600328b2decShenning 				if (ic6 == NULL)
601328b2decShenning 					printf("%u) ", r->return_icmp6 & 255);
602328b2decShenning 				else
603328b2decShenning 					printf("%s) ", ic6->name);
604328b2decShenning 				break;
605328b2decShenning 			}
606acf2444cShenning 		} else
607acf2444cShenning 			printf("drop ");
6081173271aScedric 	}
6097189e280Sdhartmei 	if (r->direction == PF_IN)
61014a9b182Skjell 		printf("in ");
6117189e280Sdhartmei 	else if (r->direction == PF_OUT)
61214a9b182Skjell 		printf("out ");
6137242ce7aSdhartmei 	if (r->log == 1)
61414a9b182Skjell 		printf("log ");
6157242ce7aSdhartmei 	else if (r->log == 2)
6167242ce7aSdhartmei 		printf("log-all ");
61714a9b182Skjell 	if (r->quick)
61814a9b182Skjell 		printf("quick ");
6197d0c9138Shenning 	if (r->ifname[0]) {
6207d0c9138Shenning 		if (r->ifnot)
6217d0c9138Shenning 			printf("on ! %s ", r->ifname);
6227d0c9138Shenning 		else
62314a9b182Skjell 			printf("on %s ", r->ifname);
6247d0c9138Shenning 	}
625cb3a4e31Sjasoni 	if (r->rt) {
626cb3a4e31Sjasoni 		if (r->rt == PF_ROUTETO)
627cb3a4e31Sjasoni 			printf("route-to ");
628fa1cdd09Sdhartmei 		else if (r->rt == PF_REPLYTO)
629fa1cdd09Sdhartmei 			printf("reply-to ");
630cb3a4e31Sjasoni 		else if (r->rt == PF_DUPTO)
631cb3a4e31Sjasoni 			printf("dup-to ");
632cb3a4e31Sjasoni 		else if (r->rt == PF_FASTROUTE)
633cb3a4e31Sjasoni 			printf("fastroute ");
634790504a6Sdhartmei 		if (r->rt != PF_FASTROUTE) {
635e8793aa9Smcbride 			print_pool(&r->rpool, 0, 0, r->af, PF_PASS);
636790504a6Sdhartmei 			printf(" ");
637790504a6Sdhartmei 		}
638cb3a4e31Sjasoni 	}
63930620b12Sfrantzen 	if (r->af) {
64030620b12Sfrantzen 		if (r->af == AF_INET)
64130620b12Sfrantzen 			printf("inet ");
64230620b12Sfrantzen 		else
64330620b12Sfrantzen 			printf("inet6 ");
64430620b12Sfrantzen 	}
64514a9b182Skjell 	if (r->proto) {
646e4ebe044Shenning 		struct protoent	*p;
647ed99c291Sderaadt 
648e4ebe044Shenning 		if ((p = getprotobynumber(r->proto)) != NULL)
64914a9b182Skjell 			printf("proto %s ", p->p_name);
65014a9b182Skjell 		else
65114a9b182Skjell 			printf("proto %u ", r->proto);
65214a9b182Skjell 	}
65344f5ed0aScedric 	print_fromto(&r->src, &r->dst, r->af, r->proto, verbose);
654c16ab608Sdhartmei 	if (r->uid.op)
6551173271aScedric 		print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
6561173271aScedric 		    UID_MAX);
657c16ab608Sdhartmei 	if (r->gid.op)
6581173271aScedric 		print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
6591173271aScedric 		    GID_MAX);
66014a9b182Skjell 	if (r->flags || r->flagset) {
66114a9b182Skjell 		printf("flags ");
66214a9b182Skjell 		print_flags(r->flags);
66314a9b182Skjell 		printf("/");
66414a9b182Skjell 		print_flags(r->flagset);
66514a9b182Skjell 		printf(" ");
66614a9b182Skjell 	}
667082ebc44Swilfried 	if (r->type) {
668b49ca6bbShenning 		const struct icmptypeent	*it;
669082ebc44Swilfried 
670b49ca6bbShenning 		it = geticmptypebynumber(r->type-1, r->af);
671d14c53d7Swilfried 		if (r->af != AF_INET6)
672d14c53d7Swilfried 			printf("icmp-type");
673082ebc44Swilfried 		else
674d0cb3502Smcbride 			printf("icmp6-type");
675b49ca6bbShenning 		if (it != NULL)
676b49ca6bbShenning 			printf(" %s ", it->name);
677d14c53d7Swilfried 		else
678d14c53d7Swilfried 			printf(" %u ", r->type-1);
679082ebc44Swilfried 		if (r->code) {
680b49ca6bbShenning 			const struct icmpcodeent	*ic;
681082ebc44Swilfried 
682b49ca6bbShenning 			ic = geticmpcodebynumber(r->type-1, r->code-1, r->af);
683b49ca6bbShenning 			if (ic != NULL)
684b49ca6bbShenning 				printf("code %s ", ic->name);
685082ebc44Swilfried 			else
68614a9b182Skjell 				printf("code %u ", r->code-1);
687082ebc44Swilfried 		}
688082ebc44Swilfried 	}
689e4cbe364Sdhartmei 	if (r->tos)
690e4cbe364Sdhartmei 		printf("tos 0x%2.2x ", r->tos);
691b96c47abSfrantzen 	if (r->keep_state == PF_STATE_NORMAL)
69214a9b182Skjell 		printf("keep state ");
693b96c47abSfrantzen 	else if (r->keep_state == PF_STATE_MODULATE)
694b96c47abSfrantzen 		printf("modulate state ");
695cc5f0329Sdhartmei 	opts = 0;
696b3c86969Sdhartmei 	if (r->max_states)
697cc5f0329Sdhartmei 		opts = 1;
698cc5f0329Sdhartmei 	for (i = 0; !opts && i < PFTM_MAX; ++i)
699cc5f0329Sdhartmei 		if (r->timeout[i])
700cc5f0329Sdhartmei 			opts = 1;
701cc5f0329Sdhartmei 	if (opts) {
702cc5f0329Sdhartmei 		printf("(");
703cc5f0329Sdhartmei 		if (r->max_states) {
704cc5f0329Sdhartmei 			printf("max %u", r->max_states);
705cc5f0329Sdhartmei 			opts = 0;
706cc5f0329Sdhartmei 		}
707cc5f0329Sdhartmei 		for (i = 0; i < PFTM_MAX; ++i)
708cc5f0329Sdhartmei 			if (r->timeout[i]) {
709cc5f0329Sdhartmei 				if (!opts)
710cc5f0329Sdhartmei 					printf(", ");
711cc5f0329Sdhartmei 				opts = 0;
712cc5f0329Sdhartmei 				printf("%s %u", pf_timeouts[i].name,
713cc5f0329Sdhartmei 				    r->timeout[i]);
714cc5f0329Sdhartmei 			}
715cc5f0329Sdhartmei 		printf(") ");
716cc5f0329Sdhartmei 	}
7176673dee2Sdhartmei 	if (r->rule_flag & PFRULE_FRAGMENT)
7186673dee2Sdhartmei 		printf("fragment ");
71967d2a440Sprovos 	if (r->rule_flag & PFRULE_NODF)
72067d2a440Sprovos 		printf("no-df ");
721edbe3066Sdhartmei 	if (r->rule_flag & PFRULE_RANDOMID)
722edbe3066Sdhartmei 		printf("random-id ");
723e258bfd4Sprovos 	if (r->min_ttl)
72434c76dcbSprovos 		printf("min-ttl %d ", r->min_ttl);
725cfa91859Sjasoni 	if (r->max_mss)
726cfa91859Sjasoni 		printf("max-mss %d ", r->max_mss);
727f48d62b3Sdhartmei 	if (r->allow_opts)
728f48d62b3Sdhartmei 		printf("allow-opts ");
729b02af636Sfrantzen 	if (r->action == PF_SCRUB) {
730b02af636Sfrantzen 		if (r->rule_flag & PFRULE_FRAGDROP)
731b02af636Sfrantzen 			printf("fragment drop-ovl ");
732b02af636Sfrantzen 		else if (r->rule_flag & PFRULE_FRAGCROP)
733b02af636Sfrantzen 			printf("fragment crop ");
734b02af636Sfrantzen 		else
735b02af636Sfrantzen 			printf("fragment reassemble ");
736b02af636Sfrantzen 	}
737455ef0c1Sdhartmei 	if (r->label[0])
738ff45dfa8Scamield 		printf("label \"%s\" ", r->label);
739f98324c6Shenning 	if (r->qname[0] && r->pqname[0])
740f98324c6Shenning 		printf("queue(%s, %s) ", r->qname, r->pqname);
741f98324c6Shenning 	else if (r->qname[0])
74278e1d2a6Shenning 		printf("queue %s ", r->qname);
7438aecb81aShenning 	if (r->tagname[0])
7448aecb81aShenning 		printf("tag %s ", r->tagname);
7458aecb81aShenning 	if (r->match_tagname[0])
7460a5f7f2fShenning 		printf("tagged %s ", r->match_tagname);
747*d0aca2f2Shenning 	if (!r->anchorname[0] && (r->action == PF_NAT ||
748*d0aca2f2Shenning 	    r->action == PF_BINAT || r->action == PF_RDR)) {
749*d0aca2f2Shenning 		printf("-> ");
750*d0aca2f2Shenning 		print_pool(&r->rpool, r->rpool.proxy_port[0],
751*d0aca2f2Shenning 		    r->rpool.proxy_port[1], r->af, r->action);
752*d0aca2f2Shenning 	}
75314a9b182Skjell 	printf("\n");
75414a9b182Skjell }
75514a9b182Skjell 
7561f8f21bdSmillert int
757ff352a37Smarkus parse_flags(char *s)
75814a9b182Skjell {
759ff352a37Smarkus 	char		*p, *q;
76014a9b182Skjell 	u_int8_t	 f = 0;
76181a15e5dSderaadt 
762ff352a37Smarkus 	for (p = s; *p; p++) {
763ff352a37Smarkus 		if ((q = strchr(tcpflags, *p)) == NULL)
764ff352a37Smarkus 			return -1;
765ff352a37Smarkus 		else
766ff352a37Smarkus 			f |= 1 << (q - tcpflags);
76714a9b182Skjell 	}
768bc795af0Shugh 	return (f ? f : PF_TH_ALL);
76914a9b182Skjell }
77094e9410bShenning 
77194e9410bShenning void
77294e9410bShenning set_ipmask(struct node_host *h, u_int8_t b)
77394e9410bShenning {
77494e9410bShenning 	struct pf_addr	*m, *n;
77594e9410bShenning 	int		 i, j = 0;
77694e9410bShenning 
77794e9410bShenning 	m = &h->addr.v.a.mask;
77894e9410bShenning 
77994e9410bShenning 	for (i = 0; i < 4; i++)
78094e9410bShenning 		m->addr32[i] = 0;
78194e9410bShenning 
78294e9410bShenning 	while (b >= 32) {
78394e9410bShenning 		m->addr32[j++] = 0xffffffff;
78494e9410bShenning 		b -= 32;
78594e9410bShenning 	}
78694e9410bShenning 	for (i = 31; i > 31-b; --i)
78794e9410bShenning 		m->addr32[j] |= (1 << i);
78894e9410bShenning 	if (b)
78994e9410bShenning 		m->addr32[j] = htonl(m->addr32[j]);
79094e9410bShenning 
79194e9410bShenning 	/* Mask off bits of the address that will never be used. */
79294e9410bShenning 	n = &h->addr.v.a.addr;
79394e9410bShenning 	for (i = 0; i < 4; i++)
79494e9410bShenning 		n->addr32[i] = n->addr32[i] & m->addr32[i];
79594e9410bShenning }
79694e9410bShenning 
79794e9410bShenning /* interface lookup routines */
79894e9410bShenning 
79994e9410bShenning struct node_host	*iftab;
80094e9410bShenning 
80194e9410bShenning void
80294e9410bShenning ifa_load(void)
80394e9410bShenning {
80494e9410bShenning 	struct ifaddrs		*ifap, *ifa;
80594e9410bShenning 	struct node_host	*n = NULL, *h = NULL;
80694e9410bShenning 
80794e9410bShenning 	if (getifaddrs(&ifap) < 0)
80894e9410bShenning 		err(1, "getifaddrs");
80994e9410bShenning 
81094e9410bShenning 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
81194e9410bShenning 		if (!(ifa->ifa_addr->sa_family == AF_INET ||
81294e9410bShenning 		    ifa->ifa_addr->sa_family == AF_INET6 ||
81394e9410bShenning 		    ifa->ifa_addr->sa_family == AF_LINK))
81494e9410bShenning 				continue;
81594e9410bShenning 		n = calloc(1, sizeof(struct node_host));
81694e9410bShenning 		if (n == NULL)
81794e9410bShenning 			err(1, "address: calloc");
81894e9410bShenning 		n->af = ifa->ifa_addr->sa_family;
81994e9410bShenning 		n->ifa_flags = ifa->ifa_flags;
82094e9410bShenning #ifdef __KAME__
82194e9410bShenning 		if (n->af == AF_INET6 &&
82294e9410bShenning 		    IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)
82394e9410bShenning 		    ifa->ifa_addr)->sin6_addr) &&
82494e9410bShenning 		    ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) {
82594e9410bShenning 			struct sockaddr_in6	*sin6;
82694e9410bShenning 
82794e9410bShenning 			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
82894e9410bShenning 			sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
82994e9410bShenning 			    sin6->sin6_addr.s6_addr[3];
83094e9410bShenning 			sin6->sin6_addr.s6_addr[2] = 0;
83194e9410bShenning 			sin6->sin6_addr.s6_addr[3] = 0;
83294e9410bShenning 		}
83394e9410bShenning #endif
83494e9410bShenning 		n->ifindex = 0;
83594e9410bShenning 		if (n->af == AF_INET) {
83694e9410bShenning 			memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *)
83794e9410bShenning 			    ifa->ifa_addr)->sin_addr.s_addr,
83894e9410bShenning 			    sizeof(struct in_addr));
83994e9410bShenning 			memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *)
84094e9410bShenning 			    ifa->ifa_netmask)->sin_addr.s_addr,
84194e9410bShenning 			    sizeof(struct in_addr));
84294e9410bShenning 			if (ifa->ifa_broadaddr != NULL)
84394e9410bShenning 				memcpy(&n->bcast, &((struct sockaddr_in *)
84494e9410bShenning 				    ifa->ifa_broadaddr)->sin_addr.s_addr,
84594e9410bShenning 				    sizeof(struct in_addr));
84694e9410bShenning 		} else if (n->af == AF_INET6) {
84794e9410bShenning 			memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *)
84894e9410bShenning 			    ifa->ifa_addr)->sin6_addr.s6_addr,
84994e9410bShenning 			    sizeof(struct in6_addr));
85094e9410bShenning 			memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *)
85194e9410bShenning 			    ifa->ifa_netmask)->sin6_addr.s6_addr,
85294e9410bShenning 			    sizeof(struct in6_addr));
85394e9410bShenning 			if (ifa->ifa_broadaddr != NULL)
85494e9410bShenning 				memcpy(&n->bcast, &((struct sockaddr_in6 *)
85594e9410bShenning 				    ifa->ifa_broadaddr)->sin6_addr.s6_addr,
85694e9410bShenning 				    sizeof(struct in6_addr));
85794e9410bShenning 			n->ifindex = ((struct sockaddr_in6 *)
85894e9410bShenning 			    ifa->ifa_addr)->sin6_scope_id;
85994e9410bShenning 		}
86094e9410bShenning 		if ((n->ifname = strdup(ifa->ifa_name)) == NULL)
86194e9410bShenning 			err(1, "ifa_load: strdup");
86294e9410bShenning 		n->next = NULL;
86394e9410bShenning 		n->tail = n;
86494e9410bShenning 		if (h == NULL)
86594e9410bShenning 			h = n;
86694e9410bShenning 		else {
86794e9410bShenning 			h->tail->next = n;
86894e9410bShenning 			h->tail = n;
86994e9410bShenning 		}
87094e9410bShenning 	}
87194e9410bShenning 	iftab = h;
87294e9410bShenning 	freeifaddrs(ifap);
87394e9410bShenning }
87494e9410bShenning 
87594e9410bShenning struct node_host *
8766cba701cShenning ifa_exists(const char *ifa_name)
87794e9410bShenning {
87894e9410bShenning 	struct node_host	*n;
87994e9410bShenning 
88094e9410bShenning 	if (iftab == NULL)
88194e9410bShenning 		ifa_load();
88294e9410bShenning 
88394e9410bShenning 	for (n = iftab; n; n = n->next) {
88494e9410bShenning 		if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
88594e9410bShenning 			return (n);
88694e9410bShenning 	}
88794e9410bShenning 	return (NULL);
88894e9410bShenning }
88994e9410bShenning 
89094e9410bShenning struct node_host *
8916cba701cShenning ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode)
89294e9410bShenning {
89394e9410bShenning 	struct node_host	*p = NULL, *h = NULL, *n = NULL;
89494e9410bShenning 	int			 return_all = 0;
89594e9410bShenning 
89694e9410bShenning 	if (!strncmp(ifa_name, "self", IFNAMSIZ))
89794e9410bShenning 		return_all = 1;
89894e9410bShenning 
89994e9410bShenning 	if (iftab == NULL)
90094e9410bShenning 		ifa_load();
90194e9410bShenning 
90294e9410bShenning 	for (p = iftab; p; p = p->next) {
90394e9410bShenning 		if (!((p->af == AF_INET || p->af == AF_INET6) &&
90494e9410bShenning 		    (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all)))
90594e9410bShenning 			continue;
90694e9410bShenning 		if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
90794e9410bShenning 			continue;
90894e9410bShenning 		if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
90994e9410bShenning 			continue;
91094e9410bShenning 		n = calloc(1, sizeof(struct node_host));
91194e9410bShenning 		if (n == NULL)
91294e9410bShenning 			err(1, "address: calloc");
91394e9410bShenning 		n->af = p->af;
91494e9410bShenning 		if (mode == PFCTL_IFLOOKUP_BCAST)
91594e9410bShenning 			memcpy(&n->addr.v.a.addr, &p->bcast,
91694e9410bShenning 			    sizeof(struct pf_addr));
91794e9410bShenning 		else
91894e9410bShenning 			memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr,
91994e9410bShenning 			    sizeof(struct pf_addr));
92094e9410bShenning 		if (mode == PFCTL_IFLOOKUP_NET)
92194e9410bShenning 			set_ipmask(n, unmask(&p->addr.v.a.mask, n->af));
92294e9410bShenning 		else {
92394e9410bShenning 			if (n->af == AF_INET) {
92494e9410bShenning 				if (p->ifa_flags & IFF_LOOPBACK &&
92594e9410bShenning 				    p->ifa_flags & IFF_LINK1)
92694e9410bShenning 					memcpy(&n->addr.v.a.mask,
92794e9410bShenning 					    &p->addr.v.a.mask,
92894e9410bShenning 					    sizeof(struct pf_addr));
92994e9410bShenning 				else
93094e9410bShenning 					set_ipmask(n, 32);
93194e9410bShenning 			} else
93294e9410bShenning 				set_ipmask(n, 128);
93394e9410bShenning 		}
93494e9410bShenning 		n->ifindex = p->ifindex;
93594e9410bShenning 
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 	if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) {
94694e9410bShenning 		fprintf(stderr, "no IP address found for %s\n", ifa_name);
94794e9410bShenning 	}
94894e9410bShenning 	return (h);
94994e9410bShenning }
95094e9410bShenning 
95194e9410bShenning struct node_host *
952f23861c1Shenning host(const char *s)
95394e9410bShenning {
9542a6c1abaShenning 	struct node_host	*h = NULL;
955f23861c1Shenning 	int			 mask, v4mask, v6mask, cont = 1;
956f23861c1Shenning 	char			*p, *q, *ps;
95794e9410bShenning 
95894e9410bShenning 	if ((p = strrchr(s, '/')) != NULL) {
95994e9410bShenning 		mask = strtol(p+1, &q, 0);
96094e9410bShenning 		if (!q || *q) {
96194e9410bShenning 			fprintf(stderr, "invalid netmask\n");
96294e9410bShenning 			return (NULL);
96394e9410bShenning 		}
964a81c851cShenning 		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
96594e9410bShenning 			err(1, "host: malloc");
96694e9410bShenning 		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
96794e9410bShenning 		v4mask = v6mask = mask;
96894e9410bShenning 	} else {
969f23861c1Shenning 		if ((ps = strdup(s)) == NULL)
970f23861c1Shenning 			err(1, "host: strdup");
97194e9410bShenning 		v4mask = 32;
97294e9410bShenning 		v6mask = 128;
973f23861c1Shenning 		mask = -1;
97494e9410bShenning 	}
97594e9410bShenning 
9762a6c1abaShenning 	/* interface with this name exists? */
9774a36d485Shenning 	if (cont && (h = host_if(ps, mask)) != NULL)
9782a6c1abaShenning 		cont = 0;
9792a6c1abaShenning 
9802a6c1abaShenning 	/* IPv4 address? */
981f23861c1Shenning 	if (cont && (h = host_v4(s, mask)) != NULL)
9822a6c1abaShenning 		cont = 0;
9832a6c1abaShenning 
9842a6c1abaShenning 	/* IPv6 address? */
9852a6c1abaShenning 	if (cont && (h = host_v6(ps, v6mask)) != NULL)
9862a6c1abaShenning 		cont = 0;
9872a6c1abaShenning 
9882a6c1abaShenning 	/* dns lookup */
9892a6c1abaShenning 	if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL)
9902a6c1abaShenning 		cont = 0;
9912a6c1abaShenning 	free(ps);
9922a6c1abaShenning 
9932a6c1abaShenning 	if (h == NULL || cont == 1) {
9942a6c1abaShenning 		fprintf(stderr, "no IP address found for %s\n", s);
9952a6c1abaShenning 		return (NULL);
9962a6c1abaShenning 	}
9972a6c1abaShenning 	return (h);
9982a6c1abaShenning }
9992a6c1abaShenning 
10002a6c1abaShenning struct node_host *
1001f2370d27Shenning host_if(const char *s, int mask)
10022a6c1abaShenning {
10032a6c1abaShenning 	struct node_host	*n, *h = NULL;
10044a36d485Shenning 	char			*p, *ps;
10054a36d485Shenning 	int			 mode = PFCTL_IFLOOKUP_HOST;
10062a6c1abaShenning 
10074a36d485Shenning 	if ((p = strrchr(s, ':')) != NULL &&
10084a36d485Shenning 	    (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) {
10094a36d485Shenning 		if (!strcmp(p+1, "network"))
10104a36d485Shenning 			mode = PFCTL_IFLOOKUP_NET;
10114a36d485Shenning 		if (!strcmp(p+1, "broadcast"))
10124a36d485Shenning 			mode = PFCTL_IFLOOKUP_BCAST;
10134a36d485Shenning 		if (mask > -1) {
10144a36d485Shenning 			fprintf(stderr, "network or broadcast lookup, but "
10154a36d485Shenning 			    "extra netmask given\n");
10164a36d485Shenning 			return (NULL);
10174a36d485Shenning 		}
10184a36d485Shenning 		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
10194a36d485Shenning 			err(1, "host: malloc");
10204a36d485Shenning 		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
10214a36d485Shenning 	} else
10224a36d485Shenning 		if ((ps = strdup(s)) == NULL)
10234a36d485Shenning 			err(1, "host_if: strdup");
10244a36d485Shenning 
10254a36d485Shenning 	if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
10262a6c1abaShenning 		/* interface with this name exists */
10274a36d485Shenning 		h = ifa_lookup(ps, mode);
10282a6c1abaShenning 		for (n = h; n != NULL && mask > -1; n = n->next)
10292a6c1abaShenning 			set_ipmask(n, mask);
10302a6c1abaShenning 	}
10314a36d485Shenning 
10324a36d485Shenning 	free(ps);
10332a6c1abaShenning 	return (h);
10342a6c1abaShenning }
10352a6c1abaShenning 
10362a6c1abaShenning struct node_host *
1037383ebbbfShenning host_v4(const char *s, int mask)
10382a6c1abaShenning {
10392a6c1abaShenning 	struct node_host	*h = NULL;
10402a6c1abaShenning 	struct in_addr		 ina;
10412a6c1abaShenning 	int			 bits;
10422a6c1abaShenning 
104394e9410bShenning 	memset(&ina, 0, sizeof(struct in_addr));
10443c58a40aScedric 	if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) > -1) {
104594e9410bShenning 		h = calloc(1, sizeof(struct node_host));
104694e9410bShenning 		if (h == NULL)
104794e9410bShenning 			err(1, "address: calloc");
104894e9410bShenning 		h->ifname = NULL;
104994e9410bShenning 		h->af = AF_INET;
105094e9410bShenning 		h->addr.v.a.addr.addr32[0] = ina.s_addr;
105194e9410bShenning 		set_ipmask(h, bits);
105294e9410bShenning 		h->next = NULL;
105394e9410bShenning 		h->tail = h;
105494e9410bShenning 	}
10552a6c1abaShenning 
105694e9410bShenning 	return (h);
105794e9410bShenning }
10582a6c1abaShenning 
10592a6c1abaShenning struct node_host *
1060f2370d27Shenning host_v6(const char *s, int mask)
10612a6c1abaShenning {
10622a6c1abaShenning 	struct addrinfo		 hints, *res;
10632a6c1abaShenning 	struct node_host	*h = NULL;
106494e9410bShenning 
106594e9410bShenning 	memset(&hints, 0, sizeof(hints));
106694e9410bShenning 	hints.ai_family = AF_INET6;
106794e9410bShenning 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
106894e9410bShenning 	hints.ai_flags = AI_NUMERICHOST;
10692a6c1abaShenning 	if (getaddrinfo(s, "0", &hints, &res) == 0) {
10702a6c1abaShenning 		h = calloc(1, sizeof(struct node_host));
10712a6c1abaShenning 		if (h == NULL)
107294e9410bShenning 			err(1, "address: calloc");
10732a6c1abaShenning 		h->ifname = NULL;
10742a6c1abaShenning 		h->af = AF_INET6;
10752a6c1abaShenning 		memcpy(&h->addr.v.a.addr,
107694e9410bShenning 		    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
10772a6c1abaShenning 		    sizeof(h->addr.v.a.addr));
10782a6c1abaShenning 		h->ifindex =
10792a6c1abaShenning 		    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
10802a6c1abaShenning 		set_ipmask(h, mask);
108194e9410bShenning 		freeaddrinfo(res);
10822a6c1abaShenning 		h->next = NULL;
10832a6c1abaShenning 		h->tail = h;
108494e9410bShenning 	}
108594e9410bShenning 
10862a6c1abaShenning 	return (h);
10872a6c1abaShenning }
10882a6c1abaShenning 
10892a6c1abaShenning struct node_host *
1090f2370d27Shenning host_dns(const char *s, int v4mask, int v6mask)
10912a6c1abaShenning {
10922a6c1abaShenning 	struct addrinfo		 hints, *res0, *res;
10932a6c1abaShenning 	struct node_host	*n, *h = NULL;
10942a6c1abaShenning 	int			 error;
10952a6c1abaShenning 
109694e9410bShenning 	memset(&hints, 0, sizeof(hints));
109794e9410bShenning 	hints.ai_family = PF_UNSPEC;
109894e9410bShenning 	hints.ai_socktype = SOCK_STREAM; /* DUMMY */
10992a6c1abaShenning 	error = getaddrinfo(s, NULL, &hints, &res0);
11002a6c1abaShenning 	if (error)
11012a6c1abaShenning 		return (h);
11022a6c1abaShenning 
110394e9410bShenning 	for (res = res0; res; res = res->ai_next) {
110494e9410bShenning 		if (res->ai_family != AF_INET &&
110594e9410bShenning 		    res->ai_family != AF_INET6)
110694e9410bShenning 			continue;
110794e9410bShenning 		n = calloc(1, sizeof(struct node_host));
110894e9410bShenning 		if (n == NULL)
11092a6c1abaShenning 			err(1, "host_dns: calloc");
111094e9410bShenning 		n->ifname = NULL;
111194e9410bShenning 		n->af = res->ai_family;
111294e9410bShenning 		if (res->ai_family == AF_INET) {
111394e9410bShenning 			memcpy(&n->addr.v.a.addr,
11142a6c1abaShenning 			    &((struct sockaddr_in *)
11152a6c1abaShenning 			    res->ai_addr)->sin_addr.s_addr,
111694e9410bShenning 			    sizeof(struct in_addr));
111794e9410bShenning 			set_ipmask(n, v4mask);
111894e9410bShenning 		} else {
111994e9410bShenning 			memcpy(&n->addr.v.a.addr,
11202a6c1abaShenning 			    &((struct sockaddr_in6 *)
11212a6c1abaShenning 			    res->ai_addr)->sin6_addr.s6_addr,
112294e9410bShenning 			    sizeof(struct in6_addr));
112394e9410bShenning 			n->ifindex =
11242a6c1abaShenning 			    ((struct sockaddr_in6 *)
11252a6c1abaShenning 			    res->ai_addr)->sin6_scope_id;
112694e9410bShenning 			set_ipmask(n, v6mask);
112794e9410bShenning 		}
112894e9410bShenning 		n->next = NULL;
112994e9410bShenning 		n->tail = n;
113094e9410bShenning 		if (h == NULL)
113194e9410bShenning 			h = n;
113294e9410bShenning 		else {
113394e9410bShenning 			h->tail->next = n;
113494e9410bShenning 			h->tail = n;
113594e9410bShenning 		}
113694e9410bShenning 	}
113794e9410bShenning 	freeaddrinfo(res0);
113894e9410bShenning 
113994e9410bShenning 	return (h);
114094e9410bShenning }
1141