Deleted Added
full compact
pfctl_parser.c (126354) pfctl_parser.c (126355)
1/* $FreeBSD: head/contrib/pf/pfctl/pfctl_parser.c 126355 2004-02-28 17:32:53Z mlaier $ */
1/* $OpenBSD: pfctl_parser.c,v 1.175 2003/09/18 20:27:58 cedric Exp $ */
2
3/*
4 * Copyright (c) 2001 Daniel Hartmeier
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <net/if.h>
36#include <netinet/in.h>
37#include <netinet/in_systm.h>
38#include <netinet/ip.h>
39#include <netinet/ip_icmp.h>
40#include <netinet/icmp6.h>
41#include <net/pfvar.h>
42#include <arpa/inet.h>
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <ctype.h>
48#include <netdb.h>
49#include <stdarg.h>
50#include <errno.h>
51#include <err.h>
52#include <ifaddrs.h>
53
2/* $OpenBSD: pfctl_parser.c,v 1.175 2003/09/18 20:27:58 cedric Exp $ */
3
4/*
5 * Copyright (c) 2001 Daniel Hartmeier
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * - Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <net/if.h>
37#include <netinet/in.h>
38#include <netinet/in_systm.h>
39#include <netinet/ip.h>
40#include <netinet/ip_icmp.h>
41#include <netinet/icmp6.h>
42#include <net/pfvar.h>
43#include <arpa/inet.h>
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <ctype.h>
49#include <netdb.h>
50#include <stdarg.h>
51#include <errno.h>
52#include <err.h>
53#include <ifaddrs.h>
54
55#if defined(__FreeBSD__)
56#include <inttypes.h>
57#else
58#define PRIu64 "llu"
59#define PRId64 "lld"
60#endif
61
54#include "pfctl_parser.h"
55#include "pfctl.h"
56
57void print_op (u_int8_t, const char *, const char *);
58void print_port (u_int8_t, u_int16_t, u_int16_t, const char *);
59void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
60void print_flags (u_int8_t);
61void print_fromto(struct pf_rule_addr *, pf_osfp_t,
62 struct pf_rule_addr *, u_int8_t, u_int8_t, int);
63
64struct node_host *host_if(const char *, int);
65struct node_host *host_v4(const char *, int);
66struct node_host *host_v6(const char *, int);
67struct node_host *host_dns(const char *, int, int);
68
69const char *tcpflags = "FSRPAUEW";
70
71static const struct icmptypeent icmp_type[] = {
72 { "echoreq", ICMP_ECHO },
73 { "echorep", ICMP_ECHOREPLY },
74 { "unreach", ICMP_UNREACH },
75 { "squench", ICMP_SOURCEQUENCH },
76 { "redir", ICMP_REDIRECT },
77 { "althost", ICMP_ALTHOSTADDR },
78 { "routeradv", ICMP_ROUTERADVERT },
79 { "routersol", ICMP_ROUTERSOLICIT },
80 { "timex", ICMP_TIMXCEED },
81 { "paramprob", ICMP_PARAMPROB },
82 { "timereq", ICMP_TSTAMP },
83 { "timerep", ICMP_TSTAMPREPLY },
84 { "inforeq", ICMP_IREQ },
85 { "inforep", ICMP_IREQREPLY },
86 { "maskreq", ICMP_MASKREQ },
87 { "maskrep", ICMP_MASKREPLY },
88 { "trace", ICMP_TRACEROUTE },
89 { "dataconv", ICMP_DATACONVERR },
90 { "mobredir", ICMP_MOBILE_REDIRECT },
91 { "ipv6-where", ICMP_IPV6_WHEREAREYOU },
92 { "ipv6-here", ICMP_IPV6_IAMHERE },
93 { "mobregreq", ICMP_MOBILE_REGREQUEST },
94 { "mobregrep", ICMP_MOBILE_REGREPLY },
95 { "skip", ICMP_SKIP },
96 { "photuris", ICMP_PHOTURIS }
97};
98
99static const struct icmptypeent icmp6_type[] = {
100 { "unreach", ICMP6_DST_UNREACH },
101 { "toobig", ICMP6_PACKET_TOO_BIG },
102 { "timex", ICMP6_TIME_EXCEEDED },
103 { "paramprob", ICMP6_PARAM_PROB },
104 { "echoreq", ICMP6_ECHO_REQUEST },
105 { "echorep", ICMP6_ECHO_REPLY },
106 { "groupqry", ICMP6_MEMBERSHIP_QUERY },
107 { "listqry", MLD_LISTENER_QUERY },
108 { "grouprep", ICMP6_MEMBERSHIP_REPORT },
109 { "listenrep", MLD_LISTENER_REPORT },
110 { "groupterm", ICMP6_MEMBERSHIP_REDUCTION },
111 { "listendone", MLD_LISTENER_DONE },
112 { "routersol", ND_ROUTER_SOLICIT },
113 { "routeradv", ND_ROUTER_ADVERT },
114 { "neighbrsol", ND_NEIGHBOR_SOLICIT },
115 { "neighbradv", ND_NEIGHBOR_ADVERT },
116 { "redir", ND_REDIRECT },
117 { "routrrenum", ICMP6_ROUTER_RENUMBERING },
118 { "wrureq", ICMP6_WRUREQUEST },
119 { "wrurep", ICMP6_WRUREPLY },
120 { "fqdnreq", ICMP6_FQDN_QUERY },
121 { "fqdnrep", ICMP6_FQDN_REPLY },
122 { "niqry", ICMP6_NI_QUERY },
123 { "nirep", ICMP6_NI_REPLY },
124 { "mtraceresp", MLD_MTRACE_RESP },
125 { "mtrace", MLD_MTRACE }
126};
127
128static const struct icmpcodeent icmp_code[] = {
129 { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET },
130 { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST },
131 { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL },
132 { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT },
133 { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG },
134 { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL },
135 { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN },
136 { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN },
137 { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED },
138 { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB },
139 { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB },
140 { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET },
141 { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST },
142 { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB },
143 { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE },
144 { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF },
145 { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET },
146 { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST },
147 { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET },
148 { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST },
149 { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
150 { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
151 { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS },
152 { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS },
153 { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR },
154 { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT },
155 { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH },
156 { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX },
157 { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED },
158 { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED }
159};
160
161static const struct icmpcodeent icmp6_code[] = {
162 { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
163 { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
164 { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR },
165 { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
166 { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
167 { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
168 { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
169 { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
170 { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
171 { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
172 { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
173 { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER }
174};
175
176const struct pf_timeout pf_timeouts[] = {
177 { "tcp.first", PFTM_TCP_FIRST_PACKET },
178 { "tcp.opening", PFTM_TCP_OPENING },
179 { "tcp.established", PFTM_TCP_ESTABLISHED },
180 { "tcp.closing", PFTM_TCP_CLOSING },
181 { "tcp.finwait", PFTM_TCP_FIN_WAIT },
182 { "tcp.closed", PFTM_TCP_CLOSED },
183 { "udp.first", PFTM_UDP_FIRST_PACKET },
184 { "udp.single", PFTM_UDP_SINGLE },
185 { "udp.multiple", PFTM_UDP_MULTIPLE },
186 { "icmp.first", PFTM_ICMP_FIRST_PACKET },
187 { "icmp.error", PFTM_ICMP_ERROR_REPLY },
188 { "other.first", PFTM_OTHER_FIRST_PACKET },
189 { "other.single", PFTM_OTHER_SINGLE },
190 { "other.multiple", PFTM_OTHER_MULTIPLE },
191 { "frag", PFTM_FRAG },
192 { "interval", PFTM_INTERVAL },
193 { "adaptive.start", PFTM_ADAPTIVE_START },
194 { "adaptive.end", PFTM_ADAPTIVE_END },
195 { NULL, 0 }
196};
197
198const struct icmptypeent *
199geticmptypebynumber(u_int8_t type, sa_family_t af)
200{
201 unsigned int i;
202
203 if (af != AF_INET6) {
204 for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0]));
205 i++) {
206 if (type == icmp_type[i].type)
207 return (&icmp_type[i]);
208 }
209 } else {
210 for (i=0; i < (sizeof (icmp6_type) /
211 sizeof(icmp6_type[0])); i++) {
212 if (type == icmp6_type[i].type)
213 return (&icmp6_type[i]);
214 }
215 }
216 return (NULL);
217}
218
219const struct icmptypeent *
220geticmptypebyname(char *w, sa_family_t af)
221{
222 unsigned int i;
223
224 if (af != AF_INET6) {
225 for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0]));
226 i++) {
227 if (!strcmp(w, icmp_type[i].name))
228 return (&icmp_type[i]);
229 }
230 } else {
231 for (i=0; i < (sizeof (icmp6_type) /
232 sizeof(icmp6_type[0])); i++) {
233 if (!strcmp(w, icmp6_type[i].name))
234 return (&icmp6_type[i]);
235 }
236 }
237 return (NULL);
238}
239
240const struct icmpcodeent *
241geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
242{
243 unsigned int i;
244
245 if (af != AF_INET6) {
246 for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0]));
247 i++) {
248 if (type == icmp_code[i].type &&
249 code == icmp_code[i].code)
250 return (&icmp_code[i]);
251 }
252 } else {
253 for (i=0; i < (sizeof (icmp6_code) /
254 sizeof(icmp6_code[0])); i++) {
255 if (type == icmp6_code[i].type &&
256 code == icmp6_code[i].code)
257 return (&icmp6_code[i]);
258 }
259 }
260 return (NULL);
261}
262
263const struct icmpcodeent *
264geticmpcodebyname(u_long type, char *w, sa_family_t af)
265{
266 unsigned int i;
267
268 if (af != AF_INET6) {
269 for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0]));
270 i++) {
271 if (type == icmp_code[i].type &&
272 !strcmp(w, icmp_code[i].name))
273 return (&icmp_code[i]);
274 }
275 } else {
276 for (i=0; i < (sizeof (icmp6_code) /
277 sizeof(icmp6_code[0])); i++) {
278 if (type == icmp6_code[i].type &&
279 !strcmp(w, icmp6_code[i].name))
280 return (&icmp6_code[i]);
281 }
282 }
283 return (NULL);
284}
285
286void
287print_op(u_int8_t op, const char *a1, const char *a2)
288{
289 if (op == PF_OP_IRG)
290 printf(" %s >< %s", a1, a2);
291 else if (op == PF_OP_XRG)
292 printf(" %s <> %s", a1, a2);
293 else if (op == PF_OP_EQ)
294 printf(" = %s", a1);
295 else if (op == PF_OP_NE)
296 printf(" != %s", a1);
297 else if (op == PF_OP_LT)
298 printf(" < %s", a1);
299 else if (op == PF_OP_LE)
300 printf(" <= %s", a1);
301 else if (op == PF_OP_GT)
302 printf(" > %s", a1);
303 else if (op == PF_OP_GE)
304 printf(" >= %s", a1);
305 else if (op == PF_OP_RRG)
306 printf(" %s:%s", a1, a2);
307}
308
309void
310print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto)
311{
312 char a1[6], a2[6];
313 struct servent *s;
314
315 s = getservbyport(p1, proto);
316 p1 = ntohs(p1);
317 p2 = ntohs(p2);
318 snprintf(a1, sizeof(a1), "%u", p1);
319 snprintf(a2, sizeof(a2), "%u", p2);
320 printf(" port");
321 if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
322 print_op(op, s->s_name, a2);
323 else
324 print_op(op, a1, a2);
325}
326
327void
328print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
329{
330 char a1[11], a2[11];
331
332 snprintf(a1, sizeof(a1), "%u", u1);
333 snprintf(a2, sizeof(a2), "%u", u2);
334 printf(" %s", t);
335 if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
336 print_op(op, "unknown", a2);
337 else
338 print_op(op, a1, a2);
339}
340
341void
342print_flags(u_int8_t f)
343{
344 int i;
345
346 for (i = 0; tcpflags[i]; ++i)
347 if (f & (1 << i))
348 printf("%c", tcpflags[i]);
349}
350
351void
352print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst,
353 sa_family_t af, u_int8_t proto, int verbose)
354{
355 char buf[PF_OSFP_LEN*3];
356 if (src->addr.type == PF_ADDR_ADDRMASK &&
357 dst->addr.type == PF_ADDR_ADDRMASK &&
358 PF_AZERO(&src->addr.v.a.addr, AF_INET6) &&
359 PF_AZERO(&src->addr.v.a.mask, AF_INET6) &&
360 PF_AZERO(&dst->addr.v.a.addr, AF_INET6) &&
361 PF_AZERO(&dst->addr.v.a.mask, AF_INET6) &&
362 !src->not && !dst->not &&
363 !src->port_op && !dst->port_op &&
364 osfp == PF_OSFP_ANY)
365 printf(" all");
366 else {
367 printf(" from ");
368 if (src->not)
369 printf("! ");
370 print_addr(&src->addr, af, verbose);
371 if (src->port_op)
372 print_port(src->port_op, src->port[0],
373 src->port[1],
374 proto == IPPROTO_TCP ? "tcp" : "udp");
375 if (osfp != PF_OSFP_ANY)
376 printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf,
377 sizeof(buf)));
378
379 printf(" to ");
380 if (dst->not)
381 printf("! ");
382 print_addr(&dst->addr, af, verbose);
383 if (dst->port_op)
384 print_port(dst->port_op, dst->port[0],
385 dst->port[1],
386 proto == IPPROTO_TCP ? "tcp" : "udp");
387 }
388}
389
390void
391print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2,
392 sa_family_t af, int id)
393{
394 struct pf_pooladdr *pooladdr;
395
396 if ((TAILQ_FIRST(&pool->list) != NULL) &&
397 TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
398 printf("{ ");
399 TAILQ_FOREACH(pooladdr, &pool->list, entries){
400 switch (id) {
401 case PF_NAT:
402 case PF_RDR:
403 case PF_BINAT:
404 print_addr(&pooladdr->addr, af, 0);
405 break;
406 case PF_PASS:
407 if (PF_AZERO(&pooladdr->addr.v.a.addr, af))
408 printf("%s", pooladdr->ifname);
409 else {
410 printf("(%s ", pooladdr->ifname);
411 print_addr(&pooladdr->addr, af, 0);
412 printf(")");
413 }
414 break;
415 default:
416 break;
417 }
418 if (TAILQ_NEXT(pooladdr, entries) != NULL)
419 printf(", ");
420 else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
421 printf(" }");
422 }
423 switch (id) {
424 case PF_NAT:
425 if ((p1 != PF_NAT_PROXY_PORT_LOW ||
426 p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) {
427 if (p1 == p2)
428 printf(" port %u", p1);
429 else
430 printf(" port %u:%u", p1, p2);
431 }
432 break;
433 case PF_RDR:
434 if (p1) {
435 printf(" port %u", p1);
436 if (p2 && (p2 != p1))
437 printf(":%u", p2);
438 }
439 break;
440 default:
441 break;
442 }
443 switch (pool->opts & PF_POOL_TYPEMASK) {
444 case PF_POOL_NONE:
445 break;
446 case PF_POOL_BITMASK:
447 printf(" bitmask");
448 break;
449 case PF_POOL_RANDOM:
450 printf(" random");
451 break;
452 case PF_POOL_SRCHASH:
453 printf(" source-hash 0x%08x%08x%08x%08x",
454 pool->key.key32[0], pool->key.key32[1],
455 pool->key.key32[2], pool->key.key32[3]);
456 break;
457 case PF_POOL_ROUNDROBIN:
458 printf(" round-robin");
459 break;
460 }
461 if (id == PF_NAT && p1 == 0 && p2 == 0)
462 printf(" static-port");
463}
464
465const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
466const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
467
468void
469print_status(struct pf_status *s)
470{
471 char statline[80];
472 time_t runtime;
473 int i;
474
475 runtime = time(NULL) - s->since;
476
477 if (s->running) {
478 unsigned sec, min, hrs, day = runtime;
479
480 sec = day % 60;
481 day /= 60;
482 min = day % 60;
483 day /= 60;
484 hrs = day % 24;
485 day /= 24;
486 snprintf(statline, sizeof(statline),
487 "Status: Enabled for %u days %.2u:%.2u:%.2u",
488 day, hrs, min, sec);
489 } else
490 snprintf(statline, sizeof(statline), "Status: Disabled");
491 printf("%-44s", statline);
492 switch (s->debug) {
493 case 0:
494 printf("%15s\n\n", "Debug: None");
495 break;
496 case 1:
497 printf("%15s\n\n", "Debug: Urgent");
498 break;
499 case 2:
500 printf("%15s\n\n", "Debug: Misc");
501 break;
502 }
503 if (s->ifname[0] != 0) {
504 printf("Interface Stats for %-16s %5s %16s\n",
505 s->ifname, "IPv4", "IPv6");
62#include "pfctl_parser.h"
63#include "pfctl.h"
64
65void print_op (u_int8_t, const char *, const char *);
66void print_port (u_int8_t, u_int16_t, u_int16_t, const char *);
67void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
68void print_flags (u_int8_t);
69void print_fromto(struct pf_rule_addr *, pf_osfp_t,
70 struct pf_rule_addr *, u_int8_t, u_int8_t, int);
71
72struct node_host *host_if(const char *, int);
73struct node_host *host_v4(const char *, int);
74struct node_host *host_v6(const char *, int);
75struct node_host *host_dns(const char *, int, int);
76
77const char *tcpflags = "FSRPAUEW";
78
79static const struct icmptypeent icmp_type[] = {
80 { "echoreq", ICMP_ECHO },
81 { "echorep", ICMP_ECHOREPLY },
82 { "unreach", ICMP_UNREACH },
83 { "squench", ICMP_SOURCEQUENCH },
84 { "redir", ICMP_REDIRECT },
85 { "althost", ICMP_ALTHOSTADDR },
86 { "routeradv", ICMP_ROUTERADVERT },
87 { "routersol", ICMP_ROUTERSOLICIT },
88 { "timex", ICMP_TIMXCEED },
89 { "paramprob", ICMP_PARAMPROB },
90 { "timereq", ICMP_TSTAMP },
91 { "timerep", ICMP_TSTAMPREPLY },
92 { "inforeq", ICMP_IREQ },
93 { "inforep", ICMP_IREQREPLY },
94 { "maskreq", ICMP_MASKREQ },
95 { "maskrep", ICMP_MASKREPLY },
96 { "trace", ICMP_TRACEROUTE },
97 { "dataconv", ICMP_DATACONVERR },
98 { "mobredir", ICMP_MOBILE_REDIRECT },
99 { "ipv6-where", ICMP_IPV6_WHEREAREYOU },
100 { "ipv6-here", ICMP_IPV6_IAMHERE },
101 { "mobregreq", ICMP_MOBILE_REGREQUEST },
102 { "mobregrep", ICMP_MOBILE_REGREPLY },
103 { "skip", ICMP_SKIP },
104 { "photuris", ICMP_PHOTURIS }
105};
106
107static const struct icmptypeent icmp6_type[] = {
108 { "unreach", ICMP6_DST_UNREACH },
109 { "toobig", ICMP6_PACKET_TOO_BIG },
110 { "timex", ICMP6_TIME_EXCEEDED },
111 { "paramprob", ICMP6_PARAM_PROB },
112 { "echoreq", ICMP6_ECHO_REQUEST },
113 { "echorep", ICMP6_ECHO_REPLY },
114 { "groupqry", ICMP6_MEMBERSHIP_QUERY },
115 { "listqry", MLD_LISTENER_QUERY },
116 { "grouprep", ICMP6_MEMBERSHIP_REPORT },
117 { "listenrep", MLD_LISTENER_REPORT },
118 { "groupterm", ICMP6_MEMBERSHIP_REDUCTION },
119 { "listendone", MLD_LISTENER_DONE },
120 { "routersol", ND_ROUTER_SOLICIT },
121 { "routeradv", ND_ROUTER_ADVERT },
122 { "neighbrsol", ND_NEIGHBOR_SOLICIT },
123 { "neighbradv", ND_NEIGHBOR_ADVERT },
124 { "redir", ND_REDIRECT },
125 { "routrrenum", ICMP6_ROUTER_RENUMBERING },
126 { "wrureq", ICMP6_WRUREQUEST },
127 { "wrurep", ICMP6_WRUREPLY },
128 { "fqdnreq", ICMP6_FQDN_QUERY },
129 { "fqdnrep", ICMP6_FQDN_REPLY },
130 { "niqry", ICMP6_NI_QUERY },
131 { "nirep", ICMP6_NI_REPLY },
132 { "mtraceresp", MLD_MTRACE_RESP },
133 { "mtrace", MLD_MTRACE }
134};
135
136static const struct icmpcodeent icmp_code[] = {
137 { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET },
138 { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST },
139 { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL },
140 { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT },
141 { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG },
142 { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL },
143 { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN },
144 { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN },
145 { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED },
146 { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB },
147 { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB },
148 { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET },
149 { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST },
150 { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB },
151 { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE },
152 { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF },
153 { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET },
154 { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST },
155 { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET },
156 { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST },
157 { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
158 { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
159 { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS },
160 { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS },
161 { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR },
162 { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT },
163 { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH },
164 { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX },
165 { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED },
166 { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED }
167};
168
169static const struct icmpcodeent icmp6_code[] = {
170 { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
171 { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
172 { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR },
173 { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
174 { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
175 { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
176 { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
177 { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
178 { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
179 { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
180 { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
181 { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER }
182};
183
184const struct pf_timeout pf_timeouts[] = {
185 { "tcp.first", PFTM_TCP_FIRST_PACKET },
186 { "tcp.opening", PFTM_TCP_OPENING },
187 { "tcp.established", PFTM_TCP_ESTABLISHED },
188 { "tcp.closing", PFTM_TCP_CLOSING },
189 { "tcp.finwait", PFTM_TCP_FIN_WAIT },
190 { "tcp.closed", PFTM_TCP_CLOSED },
191 { "udp.first", PFTM_UDP_FIRST_PACKET },
192 { "udp.single", PFTM_UDP_SINGLE },
193 { "udp.multiple", PFTM_UDP_MULTIPLE },
194 { "icmp.first", PFTM_ICMP_FIRST_PACKET },
195 { "icmp.error", PFTM_ICMP_ERROR_REPLY },
196 { "other.first", PFTM_OTHER_FIRST_PACKET },
197 { "other.single", PFTM_OTHER_SINGLE },
198 { "other.multiple", PFTM_OTHER_MULTIPLE },
199 { "frag", PFTM_FRAG },
200 { "interval", PFTM_INTERVAL },
201 { "adaptive.start", PFTM_ADAPTIVE_START },
202 { "adaptive.end", PFTM_ADAPTIVE_END },
203 { NULL, 0 }
204};
205
206const struct icmptypeent *
207geticmptypebynumber(u_int8_t type, sa_family_t af)
208{
209 unsigned int i;
210
211 if (af != AF_INET6) {
212 for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0]));
213 i++) {
214 if (type == icmp_type[i].type)
215 return (&icmp_type[i]);
216 }
217 } else {
218 for (i=0; i < (sizeof (icmp6_type) /
219 sizeof(icmp6_type[0])); i++) {
220 if (type == icmp6_type[i].type)
221 return (&icmp6_type[i]);
222 }
223 }
224 return (NULL);
225}
226
227const struct icmptypeent *
228geticmptypebyname(char *w, sa_family_t af)
229{
230 unsigned int i;
231
232 if (af != AF_INET6) {
233 for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0]));
234 i++) {
235 if (!strcmp(w, icmp_type[i].name))
236 return (&icmp_type[i]);
237 }
238 } else {
239 for (i=0; i < (sizeof (icmp6_type) /
240 sizeof(icmp6_type[0])); i++) {
241 if (!strcmp(w, icmp6_type[i].name))
242 return (&icmp6_type[i]);
243 }
244 }
245 return (NULL);
246}
247
248const struct icmpcodeent *
249geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
250{
251 unsigned int i;
252
253 if (af != AF_INET6) {
254 for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0]));
255 i++) {
256 if (type == icmp_code[i].type &&
257 code == icmp_code[i].code)
258 return (&icmp_code[i]);
259 }
260 } else {
261 for (i=0; i < (sizeof (icmp6_code) /
262 sizeof(icmp6_code[0])); i++) {
263 if (type == icmp6_code[i].type &&
264 code == icmp6_code[i].code)
265 return (&icmp6_code[i]);
266 }
267 }
268 return (NULL);
269}
270
271const struct icmpcodeent *
272geticmpcodebyname(u_long type, char *w, sa_family_t af)
273{
274 unsigned int i;
275
276 if (af != AF_INET6) {
277 for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0]));
278 i++) {
279 if (type == icmp_code[i].type &&
280 !strcmp(w, icmp_code[i].name))
281 return (&icmp_code[i]);
282 }
283 } else {
284 for (i=0; i < (sizeof (icmp6_code) /
285 sizeof(icmp6_code[0])); i++) {
286 if (type == icmp6_code[i].type &&
287 !strcmp(w, icmp6_code[i].name))
288 return (&icmp6_code[i]);
289 }
290 }
291 return (NULL);
292}
293
294void
295print_op(u_int8_t op, const char *a1, const char *a2)
296{
297 if (op == PF_OP_IRG)
298 printf(" %s >< %s", a1, a2);
299 else if (op == PF_OP_XRG)
300 printf(" %s <> %s", a1, a2);
301 else if (op == PF_OP_EQ)
302 printf(" = %s", a1);
303 else if (op == PF_OP_NE)
304 printf(" != %s", a1);
305 else if (op == PF_OP_LT)
306 printf(" < %s", a1);
307 else if (op == PF_OP_LE)
308 printf(" <= %s", a1);
309 else if (op == PF_OP_GT)
310 printf(" > %s", a1);
311 else if (op == PF_OP_GE)
312 printf(" >= %s", a1);
313 else if (op == PF_OP_RRG)
314 printf(" %s:%s", a1, a2);
315}
316
317void
318print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto)
319{
320 char a1[6], a2[6];
321 struct servent *s;
322
323 s = getservbyport(p1, proto);
324 p1 = ntohs(p1);
325 p2 = ntohs(p2);
326 snprintf(a1, sizeof(a1), "%u", p1);
327 snprintf(a2, sizeof(a2), "%u", p2);
328 printf(" port");
329 if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
330 print_op(op, s->s_name, a2);
331 else
332 print_op(op, a1, a2);
333}
334
335void
336print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
337{
338 char a1[11], a2[11];
339
340 snprintf(a1, sizeof(a1), "%u", u1);
341 snprintf(a2, sizeof(a2), "%u", u2);
342 printf(" %s", t);
343 if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
344 print_op(op, "unknown", a2);
345 else
346 print_op(op, a1, a2);
347}
348
349void
350print_flags(u_int8_t f)
351{
352 int i;
353
354 for (i = 0; tcpflags[i]; ++i)
355 if (f & (1 << i))
356 printf("%c", tcpflags[i]);
357}
358
359void
360print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst,
361 sa_family_t af, u_int8_t proto, int verbose)
362{
363 char buf[PF_OSFP_LEN*3];
364 if (src->addr.type == PF_ADDR_ADDRMASK &&
365 dst->addr.type == PF_ADDR_ADDRMASK &&
366 PF_AZERO(&src->addr.v.a.addr, AF_INET6) &&
367 PF_AZERO(&src->addr.v.a.mask, AF_INET6) &&
368 PF_AZERO(&dst->addr.v.a.addr, AF_INET6) &&
369 PF_AZERO(&dst->addr.v.a.mask, AF_INET6) &&
370 !src->not && !dst->not &&
371 !src->port_op && !dst->port_op &&
372 osfp == PF_OSFP_ANY)
373 printf(" all");
374 else {
375 printf(" from ");
376 if (src->not)
377 printf("! ");
378 print_addr(&src->addr, af, verbose);
379 if (src->port_op)
380 print_port(src->port_op, src->port[0],
381 src->port[1],
382 proto == IPPROTO_TCP ? "tcp" : "udp");
383 if (osfp != PF_OSFP_ANY)
384 printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf,
385 sizeof(buf)));
386
387 printf(" to ");
388 if (dst->not)
389 printf("! ");
390 print_addr(&dst->addr, af, verbose);
391 if (dst->port_op)
392 print_port(dst->port_op, dst->port[0],
393 dst->port[1],
394 proto == IPPROTO_TCP ? "tcp" : "udp");
395 }
396}
397
398void
399print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2,
400 sa_family_t af, int id)
401{
402 struct pf_pooladdr *pooladdr;
403
404 if ((TAILQ_FIRST(&pool->list) != NULL) &&
405 TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
406 printf("{ ");
407 TAILQ_FOREACH(pooladdr, &pool->list, entries){
408 switch (id) {
409 case PF_NAT:
410 case PF_RDR:
411 case PF_BINAT:
412 print_addr(&pooladdr->addr, af, 0);
413 break;
414 case PF_PASS:
415 if (PF_AZERO(&pooladdr->addr.v.a.addr, af))
416 printf("%s", pooladdr->ifname);
417 else {
418 printf("(%s ", pooladdr->ifname);
419 print_addr(&pooladdr->addr, af, 0);
420 printf(")");
421 }
422 break;
423 default:
424 break;
425 }
426 if (TAILQ_NEXT(pooladdr, entries) != NULL)
427 printf(", ");
428 else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
429 printf(" }");
430 }
431 switch (id) {
432 case PF_NAT:
433 if ((p1 != PF_NAT_PROXY_PORT_LOW ||
434 p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) {
435 if (p1 == p2)
436 printf(" port %u", p1);
437 else
438 printf(" port %u:%u", p1, p2);
439 }
440 break;
441 case PF_RDR:
442 if (p1) {
443 printf(" port %u", p1);
444 if (p2 && (p2 != p1))
445 printf(":%u", p2);
446 }
447 break;
448 default:
449 break;
450 }
451 switch (pool->opts & PF_POOL_TYPEMASK) {
452 case PF_POOL_NONE:
453 break;
454 case PF_POOL_BITMASK:
455 printf(" bitmask");
456 break;
457 case PF_POOL_RANDOM:
458 printf(" random");
459 break;
460 case PF_POOL_SRCHASH:
461 printf(" source-hash 0x%08x%08x%08x%08x",
462 pool->key.key32[0], pool->key.key32[1],
463 pool->key.key32[2], pool->key.key32[3]);
464 break;
465 case PF_POOL_ROUNDROBIN:
466 printf(" round-robin");
467 break;
468 }
469 if (id == PF_NAT && p1 == 0 && p2 == 0)
470 printf(" static-port");
471}
472
473const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
474const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
475
476void
477print_status(struct pf_status *s)
478{
479 char statline[80];
480 time_t runtime;
481 int i;
482
483 runtime = time(NULL) - s->since;
484
485 if (s->running) {
486 unsigned sec, min, hrs, day = runtime;
487
488 sec = day % 60;
489 day /= 60;
490 min = day % 60;
491 day /= 60;
492 hrs = day % 24;
493 day /= 24;
494 snprintf(statline, sizeof(statline),
495 "Status: Enabled for %u days %.2u:%.2u:%.2u",
496 day, hrs, min, sec);
497 } else
498 snprintf(statline, sizeof(statline), "Status: Disabled");
499 printf("%-44s", statline);
500 switch (s->debug) {
501 case 0:
502 printf("%15s\n\n", "Debug: None");
503 break;
504 case 1:
505 printf("%15s\n\n", "Debug: Urgent");
506 break;
507 case 2:
508 printf("%15s\n\n", "Debug: Misc");
509 break;
510 }
511 if (s->ifname[0] != 0) {
512 printf("Interface Stats for %-16s %5s %16s\n",
513 s->ifname, "IPv4", "IPv6");
506 printf(" %-25s %14llu %16llu\n", "Bytes In",
514 printf(" %-25s %14"PRIu64" %16"PRIu64"\n", "Bytes In",
507 s->bcounters[0][0], s->bcounters[1][0]);
515 s->bcounters[0][0], s->bcounters[1][0]);
508 printf(" %-25s %14llu %16llu\n", "Bytes Out",
516 printf(" %-25s %14"PRIu64" %16"PRIu64"\n", "Bytes Out",
509 s->bcounters[0][1], s->bcounters[1][1]);
510 printf(" Packets In\n");
517 s->bcounters[0][1], s->bcounters[1][1]);
518 printf(" Packets In\n");
511 printf(" %-23s %14llu %16llu\n", "Passed",
519 printf(" %-23s %14"PRIu64" %16"PRIu64"\n", "Passed",
512 s->pcounters[0][0][PF_PASS],
513 s->pcounters[1][0][PF_PASS]);
520 s->pcounters[0][0][PF_PASS],
521 s->pcounters[1][0][PF_PASS]);
514 printf(" %-23s %14llu %16llu\n", "Blocked",
522 printf(" %-23s %14"PRIu64" %16"PRIu64"\n", "Blocked",
515 s->pcounters[0][0][PF_DROP],
516 s->pcounters[1][0][PF_DROP]);
517 printf(" Packets Out\n");
523 s->pcounters[0][0][PF_DROP],
524 s->pcounters[1][0][PF_DROP]);
525 printf(" Packets Out\n");
518 printf(" %-23s %14llu %16llu\n", "Passed",
526 printf(" %-23s %14"PRIu64" %16"PRIu64"\n", "Passed",
519 s->pcounters[0][1][PF_PASS],
520 s->pcounters[1][1][PF_PASS]);
527 s->pcounters[0][1][PF_PASS],
528 s->pcounters[1][1][PF_PASS]);
521 printf(" %-23s %14llu %16llu\n\n", "Blocked",
529 printf(" %-23s %14"PRIu64" %16"PRIu64"\n\n", "Blocked",
522 s->pcounters[0][1][PF_DROP],
523 s->pcounters[1][1][PF_DROP]);
524 }
525 printf("%-27s %14s %16s\n", "State Table", "Total", "Rate");
526 printf(" %-25s %14u %14s\n", "current entries", s->states, "");
527 for (i = 0; i < FCNT_MAX; i++) {
530 s->pcounters[0][1][PF_DROP],
531 s->pcounters[1][1][PF_DROP]);
532 }
533 printf("%-27s %14s %16s\n", "State Table", "Total", "Rate");
534 printf(" %-25s %14u %14s\n", "current entries", s->states, "");
535 for (i = 0; i < FCNT_MAX; i++) {
528 printf(" %-25s %14llu", pf_fcounters[i],
529 (unsigned long long)s->fcounters[i]);
536 printf(" %-25s %14"PRIu64" ", pf_fcounters[i],
537 s->fcounters[i]);
530 if (runtime > 0)
531 printf("%14.1f/s\n",
532 (double)s->fcounters[i] / (double)runtime);
533 else
534 printf("%14s\n", "");
535 }
536 printf("Counters\n");
537 for (i = 0; i < PFRES_MAX; i++) {
538 if (runtime > 0)
539 printf("%14.1f/s\n",
540 (double)s->fcounters[i] / (double)runtime);
541 else
542 printf("%14s\n", "");
543 }
544 printf("Counters\n");
545 for (i = 0; i < PFRES_MAX; i++) {
538 printf(" %-25s %14llu ", pf_reasons[i],
539 (unsigned long long)s->counters[i]);
546 printf(" %-25s %14"PRIu64" ", pf_reasons[i],
547 s->counters[i]);
540 if (runtime > 0)
541 printf("%14.1f/s\n",
542 (double)s->counters[i] / (double)runtime);
543 else
544 printf("%14s\n", "");
545 }
546}
547
548void
549print_rule(struct pf_rule *r, int verbose)
550{
551 static const char *actiontypes[] = { "pass", "block", "scrub", "nat",
552 "no nat", "binat", "no binat", "rdr", "no rdr" };
553 static const char *anchortypes[] = { "anchor", "anchor", "anchor",
554 "nat-anchor", "nat-anchor", "binat-anchor", "binat-anchor",
555 "rdr-anchor", "rdr-anchor" };
556 int i, opts;
557
558 if (verbose)
559 printf("@%d ", r->nr);
560 if (r->action > PF_NORDR)
561 printf("action(%d)", r->action);
562 else if (r->anchorname[0])
563 printf("%s %s", anchortypes[r->action], r->anchorname);
564 else {
565 printf("%s", actiontypes[r->action]);
566 if (r->natpass)
567 printf(" pass");
568 }
569 if (r->action == PF_DROP) {
570 if (r->rule_flag & PFRULE_RETURN)
571 printf(" return");
572 else if (r->rule_flag & PFRULE_RETURNRST) {
573 if (!r->return_ttl)
574 printf(" return-rst");
575 else
576 printf(" return-rst(ttl %d)", r->return_ttl);
577 } else if (r->rule_flag & PFRULE_RETURNICMP) {
578 const struct icmpcodeent *ic, *ic6;
579
580 ic = geticmpcodebynumber(r->return_icmp >> 8,
581 r->return_icmp & 255, AF_INET);
582 ic6 = geticmpcodebynumber(r->return_icmp6 >> 8,
583 r->return_icmp6 & 255, AF_INET6);
584
585 switch(r->af) {
586 case AF_INET:
587 printf(" return-icmp");
588 if (ic == NULL)
589 printf("(%u)", r->return_icmp & 255);
590 else
591 printf("(%s)", ic->name);
592 break;
593 case AF_INET6:
594 printf(" return-icmp6");
595 if (ic6 == NULL)
596 printf("(%u)", r->return_icmp6 & 255);
597 else
598 printf("(%s)", ic6->name);
599 break;
600 default:
601 printf(" return-icmp");
602 if (ic == NULL)
603 printf("(%u, ", r->return_icmp & 255);
604 else
605 printf("(%s, ", ic->name);
606 if (ic6 == NULL)
607 printf("%u)", r->return_icmp6 & 255);
608 else
609 printf("%s)", ic6->name);
610 break;
611 }
612 } else
613 printf(" drop");
614 }
615 if (r->direction == PF_IN)
616 printf(" in");
617 else if (r->direction == PF_OUT)
618 printf(" out");
619 if (r->log == 1)
620 printf(" log");
621 else if (r->log == 2)
622 printf(" log-all");
623 if (r->quick)
624 printf(" quick");
625 if (r->ifname[0]) {
626 if (r->ifnot)
627 printf(" on ! %s", r->ifname);
628 else
629 printf(" on %s", r->ifname);
630 }
631 if (r->rt) {
632 if (r->rt == PF_ROUTETO)
633 printf(" route-to");
634 else if (r->rt == PF_REPLYTO)
635 printf(" reply-to");
636 else if (r->rt == PF_DUPTO)
637 printf(" dup-to");
638 else if (r->rt == PF_FASTROUTE)
639 printf(" fastroute");
640 if (r->rt != PF_FASTROUTE) {
641 printf(" ");
642 print_pool(&r->rpool, 0, 0, r->af, PF_PASS);
643 }
644 }
645 if (r->af) {
646 if (r->af == AF_INET)
647 printf(" inet");
648 else
649 printf(" inet6");
650 }
651 if (r->proto) {
652 struct protoent *p;
653
654 if ((p = getprotobynumber(r->proto)) != NULL)
655 printf(" proto %s", p->p_name);
656 else
657 printf(" proto %u", r->proto);
658 }
659 print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto,
660 verbose);
661 if (r->uid.op)
662 print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
663 UID_MAX);
664 if (r->gid.op)
665 print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
666 GID_MAX);
667 if (r->flags || r->flagset) {
668 printf(" flags ");
669 print_flags(r->flags);
670 printf("/");
671 print_flags(r->flagset);
672 }
673 if (r->type) {
674 const struct icmptypeent *it;
675
676 it = geticmptypebynumber(r->type-1, r->af);
677 if (r->af != AF_INET6)
678 printf(" icmp-type");
679 else
680 printf(" icmp6-type");
681 if (it != NULL)
682 printf(" %s", it->name);
683 else
684 printf(" %u", r->type-1);
685 if (r->code) {
686 const struct icmpcodeent *ic;
687
688 ic = geticmpcodebynumber(r->type-1, r->code-1, r->af);
689 if (ic != NULL)
690 printf(" code %s", ic->name);
691 else
692 printf(" code %u", r->code-1);
693 }
694 }
695 if (r->tos)
696 printf(" tos 0x%2.2x", r->tos);
697 if (r->keep_state == PF_STATE_NORMAL)
698 printf(" keep state");
699 else if (r->keep_state == PF_STATE_MODULATE)
700 printf(" modulate state");
701 else if (r->keep_state == PF_STATE_SYNPROXY)
702 printf(" synproxy state");
703 opts = 0;
704 if (r->max_states)
705 opts = 1;
706 for (i = 0; !opts && i < PFTM_MAX; ++i)
707 if (r->timeout[i])
708 opts = 1;
709 if (opts) {
710 printf(" (");
711 if (r->max_states) {
712 printf("max %u", r->max_states);
713 opts = 0;
714 }
715 for (i = 0; i < PFTM_MAX; ++i)
716 if (r->timeout[i]) {
717 if (!opts)
718 printf(", ");
719 opts = 0;
720 printf("%s %u", pf_timeouts[i].name,
721 r->timeout[i]);
722 }
723 printf(")");
724 }
725 if (r->rule_flag & PFRULE_FRAGMENT)
726 printf(" fragment");
727 if (r->rule_flag & PFRULE_NODF)
728 printf(" no-df");
729 if (r->rule_flag & PFRULE_RANDOMID)
730 printf(" random-id");
731 if (r->min_ttl)
732 printf(" min-ttl %d", r->min_ttl);
733 if (r->max_mss)
734 printf(" max-mss %d", r->max_mss);
735 if (r->allow_opts)
736 printf(" allow-opts");
737 if (r->action == PF_SCRUB) {
738 if (r->rule_flag & PFRULE_REASSEMBLE_TCP)
739 printf(" reassemble tcp");
740
741 if (r->rule_flag & PFRULE_FRAGDROP)
742 printf(" fragment drop-ovl");
743 else if (r->rule_flag & PFRULE_FRAGCROP)
744 printf(" fragment crop");
745 else
746 printf(" fragment reassemble");
747 }
748 if (r->label[0])
749 printf(" label \"%s\"", r->label);
750 if (r->qname[0] && r->pqname[0])
751 printf(" queue(%s, %s)", r->qname, r->pqname);
752 else if (r->qname[0])
753 printf(" queue %s", r->qname);
754 if (r->tagname[0])
755 printf(" tag %s", r->tagname);
756 if (r->match_tagname[0]) {
757 if (r->match_tag_not)
758 printf(" !");
759 printf(" tagged %s", r->match_tagname);
760 }
761 if (!r->anchorname[0] && (r->action == PF_NAT ||
762 r->action == PF_BINAT || r->action == PF_RDR)) {
763 printf(" -> ");
764 print_pool(&r->rpool, r->rpool.proxy_port[0],
765 r->rpool.proxy_port[1], r->af, r->action);
766 }
767 printf("\n");
768}
769
770void
771print_tabledef(const char *name, int flags, int addrs,
772 struct node_tinithead *nodes)
773{
774 struct node_tinit *ti, *nti;
775 struct node_host *h;
776
777 printf("table <%s>", name);
778 if (flags & PFR_TFLAG_CONST)
779 printf(" const");
780 if (flags & PFR_TFLAG_PERSIST)
781 printf(" persist");
782 SIMPLEQ_FOREACH(ti, nodes, entries) {
783 if (ti->file) {
784 printf(" file \"%s\"", ti->file);
785 continue;
786 }
787 printf(" {");
788 for (;;) {
789 for (h = ti->host; h != NULL; h = h->next) {
790 printf(h->not ? " !" : " ");
791 print_addr(&h->addr, h->af, 0);
792 }
793 nti = SIMPLEQ_NEXT(ti, entries);
794 if (nti != NULL && nti->file == NULL)
795 ti = nti; /* merge lists */
796 else
797 break;
798 }
799 printf(" }");
800 }
801 if (addrs && SIMPLEQ_EMPTY(nodes))
802 printf(" { }");
803 printf("\n");
804}
805
806int
807parse_flags(char *s)
808{
809 char *p, *q;
810 u_int8_t f = 0;
811
812 for (p = s; *p; p++) {
813 if ((q = strchr(tcpflags, *p)) == NULL)
814 return -1;
815 else
816 f |= 1 << (q - tcpflags);
817 }
818 return (f ? f : PF_TH_ALL);
819}
820
821void
822set_ipmask(struct node_host *h, u_int8_t b)
823{
824 struct pf_addr *m, *n;
825 int i, j = 0;
826
827 m = &h->addr.v.a.mask;
828
829 for (i = 0; i < 4; i++)
830 m->addr32[i] = 0;
831
832 while (b >= 32) {
833 m->addr32[j++] = 0xffffffff;
834 b -= 32;
835 }
836 for (i = 31; i > 31-b; --i)
837 m->addr32[j] |= (1 << i);
838 if (b)
839 m->addr32[j] = htonl(m->addr32[j]);
840
841 /* Mask off bits of the address that will never be used. */
842 n = &h->addr.v.a.addr;
843 if (h->addr.type == PF_ADDR_ADDRMASK)
844 for (i = 0; i < 4; i++)
845 n->addr32[i] = n->addr32[i] & m->addr32[i];
846}
847
848int
849check_netmask(struct node_host *h, sa_family_t af)
850{
851 struct node_host *n = NULL;
852 struct pf_addr *m;
853
854 for (n = h; n != NULL; n = n->next) {
855 if (h->addr.type == PF_ADDR_TABLE)
856 continue;
857 m = &h->addr.v.a.mask;
858 /* fix up netmask for dynaddr */
859 if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL &&
860 unmask(m, AF_INET6) > 32)
861 set_ipmask(n, 32);
862 /* netmasks > 32 bit are invalid on v4 */
863 if (af == AF_INET &&
864 (m->addr32[1] || m->addr32[2] || m->addr32[3])) {
865 fprintf(stderr, "netmask %u invalid for IPv4 address\n",
866 unmask(m, AF_INET6));
867 return (1);
868 }
869 }
870 return (0);
871}
872
873/* interface lookup routines */
874
875struct node_host *iftab;
876
877void
878ifa_load(void)
879{
880 struct ifaddrs *ifap, *ifa;
881 struct node_host *n = NULL, *h = NULL;
882
883 if (getifaddrs(&ifap) < 0)
884 err(1, "getifaddrs");
885
886 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
887 if (!(ifa->ifa_addr->sa_family == AF_INET ||
888 ifa->ifa_addr->sa_family == AF_INET6 ||
889 ifa->ifa_addr->sa_family == AF_LINK))
890 continue;
891 n = calloc(1, sizeof(struct node_host));
892 if (n == NULL)
893 err(1, "address: calloc");
894 n->af = ifa->ifa_addr->sa_family;
895 n->ifa_flags = ifa->ifa_flags;
896#ifdef __KAME__
897 if (n->af == AF_INET6 &&
898 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)
899 ifa->ifa_addr)->sin6_addr) &&
900 ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) {
901 struct sockaddr_in6 *sin6;
902
903 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
904 sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
905 sin6->sin6_addr.s6_addr[3];
906 sin6->sin6_addr.s6_addr[2] = 0;
907 sin6->sin6_addr.s6_addr[3] = 0;
908 }
909#endif
910 n->ifindex = 0;
911 if (n->af == AF_INET) {
912 memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *)
913 ifa->ifa_addr)->sin_addr.s_addr,
914 sizeof(struct in_addr));
915 memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *)
916 ifa->ifa_netmask)->sin_addr.s_addr,
917 sizeof(struct in_addr));
918 if (ifa->ifa_broadaddr != NULL)
919 memcpy(&n->bcast, &((struct sockaddr_in *)
920 ifa->ifa_broadaddr)->sin_addr.s_addr,
921 sizeof(struct in_addr));
922 } else if (n->af == AF_INET6) {
923 memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *)
924 ifa->ifa_addr)->sin6_addr.s6_addr,
925 sizeof(struct in6_addr));
926 memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *)
927 ifa->ifa_netmask)->sin6_addr.s6_addr,
928 sizeof(struct in6_addr));
929 if (ifa->ifa_broadaddr != NULL)
930 memcpy(&n->bcast, &((struct sockaddr_in6 *)
931 ifa->ifa_broadaddr)->sin6_addr.s6_addr,
932 sizeof(struct in6_addr));
933 n->ifindex = ((struct sockaddr_in6 *)
934 ifa->ifa_addr)->sin6_scope_id;
935 }
936 if ((n->ifname = strdup(ifa->ifa_name)) == NULL)
937 err(1, "ifa_load: strdup");
938 n->next = NULL;
939 n->tail = n;
940 if (h == NULL)
941 h = n;
942 else {
943 h->tail->next = n;
944 h->tail = n;
945 }
946 }
947 iftab = h;
948 freeifaddrs(ifap);
949}
950
951struct node_host *
952ifa_exists(const char *ifa_name)
953{
954 struct node_host *n;
955
956 if (iftab == NULL)
957 ifa_load();
958
959 for (n = iftab; n; n = n->next) {
960 if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
961 return (n);
962 }
963 return (NULL);
964}
965
966struct node_host *
967ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode)
968{
969 struct node_host *p = NULL, *h = NULL, *n = NULL;
970 int return_all = 0;
971
972 if (!strncmp(ifa_name, "self", IFNAMSIZ))
973 return_all = 1;
974
975 if (iftab == NULL)
976 ifa_load();
977
978 for (p = iftab; p; p = p->next) {
979 if (!((p->af == AF_INET || p->af == AF_INET6) &&
980 (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all)))
981 continue;
982 if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
983 continue;
984 if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
985 continue;
986 n = calloc(1, sizeof(struct node_host));
987 if (n == NULL)
988 err(1, "address: calloc");
989 n->af = p->af;
990 if (mode == PFCTL_IFLOOKUP_BCAST)
991 memcpy(&n->addr.v.a.addr, &p->bcast,
992 sizeof(struct pf_addr));
993 else
994 memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr,
995 sizeof(struct pf_addr));
996 if (mode == PFCTL_IFLOOKUP_NET)
997 set_ipmask(n, unmask(&p->addr.v.a.mask, n->af));
998 else {
999 if (n->af == AF_INET) {
1000 if (p->ifa_flags & IFF_LOOPBACK &&
1001 p->ifa_flags & IFF_LINK1)
1002 memcpy(&n->addr.v.a.mask,
1003 &p->addr.v.a.mask,
1004 sizeof(struct pf_addr));
1005 else
1006 set_ipmask(n, 32);
1007 } else
1008 set_ipmask(n, 128);
1009 }
1010 n->ifindex = p->ifindex;
1011
1012 n->next = NULL;
1013 n->tail = n;
1014 if (h == NULL)
1015 h = n;
1016 else {
1017 h->tail->next = n;
1018 h->tail = n;
1019 }
1020 }
1021 if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) {
1022 fprintf(stderr, "no IP address found for %s\n", ifa_name);
1023 }
1024 return (h);
1025}
1026
1027struct node_host *
1028host(const char *s)
1029{
1030 struct node_host *h = NULL;
1031 int mask, v4mask, v6mask, cont = 1;
1032 char *p, *q, *ps;
1033
1034 if ((p = strrchr(s, '/')) != NULL) {
1035 mask = strtol(p+1, &q, 0);
1036 if (!q || *q || mask > 128 || q == (p+1)) {
1037 fprintf(stderr, "invalid netmask\n");
1038 return (NULL);
1039 }
1040 if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
1041 err(1, "host: malloc");
1042 strlcpy(ps, s, strlen(s) - strlen(p) + 1);
1043 v4mask = v6mask = mask;
1044 } else {
1045 if ((ps = strdup(s)) == NULL)
1046 err(1, "host: strdup");
1047 v4mask = 32;
1048 v6mask = 128;
1049 mask = -1;
1050 }
1051
1052 /* interface with this name exists? */
1053 if (cont && (h = host_if(ps, mask)) != NULL)
1054 cont = 0;
1055
1056 /* IPv4 address? */
1057 if (cont && (h = host_v4(s, mask)) != NULL)
1058 cont = 0;
1059
1060 /* IPv6 address? */
1061 if (cont && (h = host_v6(ps, v6mask)) != NULL)
1062 cont = 0;
1063
1064 /* dns lookup */
1065 if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL)
1066 cont = 0;
1067 free(ps);
1068
1069 if (h == NULL || cont == 1) {
1070 fprintf(stderr, "no IP address found for %s\n", s);
1071 return (NULL);
1072 }
1073 return (h);
1074}
1075
1076struct node_host *
1077host_if(const char *s, int mask)
1078{
1079 struct node_host *n, *h = NULL;
1080 char *p, *ps;
1081 int mode = PFCTL_IFLOOKUP_HOST;
1082
1083 if ((p = strrchr(s, ':')) != NULL &&
1084 (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) {
1085 if (!strcmp(p+1, "network"))
1086 mode = PFCTL_IFLOOKUP_NET;
1087 if (!strcmp(p+1, "broadcast"))
1088 mode = PFCTL_IFLOOKUP_BCAST;
1089 if (mask > -1) {
1090 fprintf(stderr, "network or broadcast lookup, but "
1091 "extra netmask given\n");
1092 return (NULL);
1093 }
1094 if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
1095 err(1, "host: malloc");
1096 strlcpy(ps, s, strlen(s) - strlen(p) + 1);
1097 } else
1098 if ((ps = strdup(s)) == NULL)
1099 err(1, "host_if: strdup");
1100
1101 if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
1102 /* interface with this name exists */
1103 h = ifa_lookup(ps, mode);
1104 for (n = h; n != NULL && mask > -1; n = n->next)
1105 set_ipmask(n, mask);
1106 }
1107
1108 free(ps);
1109 return (h);
1110}
1111
1112struct node_host *
1113host_v4(const char *s, int mask)
1114{
1115 struct node_host *h = NULL;
1116 struct in_addr ina;
1117 int bits;
1118
1119 memset(&ina, 0, sizeof(struct in_addr));
1120 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) > -1) {
1121 h = calloc(1, sizeof(struct node_host));
1122 if (h == NULL)
1123 err(1, "address: calloc");
1124 h->ifname = NULL;
1125 h->af = AF_INET;
1126 h->addr.v.a.addr.addr32[0] = ina.s_addr;
548 if (runtime > 0)
549 printf("%14.1f/s\n",
550 (double)s->counters[i] / (double)runtime);
551 else
552 printf("%14s\n", "");
553 }
554}
555
556void
557print_rule(struct pf_rule *r, int verbose)
558{
559 static const char *actiontypes[] = { "pass", "block", "scrub", "nat",
560 "no nat", "binat", "no binat", "rdr", "no rdr" };
561 static const char *anchortypes[] = { "anchor", "anchor", "anchor",
562 "nat-anchor", "nat-anchor", "binat-anchor", "binat-anchor",
563 "rdr-anchor", "rdr-anchor" };
564 int i, opts;
565
566 if (verbose)
567 printf("@%d ", r->nr);
568 if (r->action > PF_NORDR)
569 printf("action(%d)", r->action);
570 else if (r->anchorname[0])
571 printf("%s %s", anchortypes[r->action], r->anchorname);
572 else {
573 printf("%s", actiontypes[r->action]);
574 if (r->natpass)
575 printf(" pass");
576 }
577 if (r->action == PF_DROP) {
578 if (r->rule_flag & PFRULE_RETURN)
579 printf(" return");
580 else if (r->rule_flag & PFRULE_RETURNRST) {
581 if (!r->return_ttl)
582 printf(" return-rst");
583 else
584 printf(" return-rst(ttl %d)", r->return_ttl);
585 } else if (r->rule_flag & PFRULE_RETURNICMP) {
586 const struct icmpcodeent *ic, *ic6;
587
588 ic = geticmpcodebynumber(r->return_icmp >> 8,
589 r->return_icmp & 255, AF_INET);
590 ic6 = geticmpcodebynumber(r->return_icmp6 >> 8,
591 r->return_icmp6 & 255, AF_INET6);
592
593 switch(r->af) {
594 case AF_INET:
595 printf(" return-icmp");
596 if (ic == NULL)
597 printf("(%u)", r->return_icmp & 255);
598 else
599 printf("(%s)", ic->name);
600 break;
601 case AF_INET6:
602 printf(" return-icmp6");
603 if (ic6 == NULL)
604 printf("(%u)", r->return_icmp6 & 255);
605 else
606 printf("(%s)", ic6->name);
607 break;
608 default:
609 printf(" return-icmp");
610 if (ic == NULL)
611 printf("(%u, ", r->return_icmp & 255);
612 else
613 printf("(%s, ", ic->name);
614 if (ic6 == NULL)
615 printf("%u)", r->return_icmp6 & 255);
616 else
617 printf("%s)", ic6->name);
618 break;
619 }
620 } else
621 printf(" drop");
622 }
623 if (r->direction == PF_IN)
624 printf(" in");
625 else if (r->direction == PF_OUT)
626 printf(" out");
627 if (r->log == 1)
628 printf(" log");
629 else if (r->log == 2)
630 printf(" log-all");
631 if (r->quick)
632 printf(" quick");
633 if (r->ifname[0]) {
634 if (r->ifnot)
635 printf(" on ! %s", r->ifname);
636 else
637 printf(" on %s", r->ifname);
638 }
639 if (r->rt) {
640 if (r->rt == PF_ROUTETO)
641 printf(" route-to");
642 else if (r->rt == PF_REPLYTO)
643 printf(" reply-to");
644 else if (r->rt == PF_DUPTO)
645 printf(" dup-to");
646 else if (r->rt == PF_FASTROUTE)
647 printf(" fastroute");
648 if (r->rt != PF_FASTROUTE) {
649 printf(" ");
650 print_pool(&r->rpool, 0, 0, r->af, PF_PASS);
651 }
652 }
653 if (r->af) {
654 if (r->af == AF_INET)
655 printf(" inet");
656 else
657 printf(" inet6");
658 }
659 if (r->proto) {
660 struct protoent *p;
661
662 if ((p = getprotobynumber(r->proto)) != NULL)
663 printf(" proto %s", p->p_name);
664 else
665 printf(" proto %u", r->proto);
666 }
667 print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto,
668 verbose);
669 if (r->uid.op)
670 print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
671 UID_MAX);
672 if (r->gid.op)
673 print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
674 GID_MAX);
675 if (r->flags || r->flagset) {
676 printf(" flags ");
677 print_flags(r->flags);
678 printf("/");
679 print_flags(r->flagset);
680 }
681 if (r->type) {
682 const struct icmptypeent *it;
683
684 it = geticmptypebynumber(r->type-1, r->af);
685 if (r->af != AF_INET6)
686 printf(" icmp-type");
687 else
688 printf(" icmp6-type");
689 if (it != NULL)
690 printf(" %s", it->name);
691 else
692 printf(" %u", r->type-1);
693 if (r->code) {
694 const struct icmpcodeent *ic;
695
696 ic = geticmpcodebynumber(r->type-1, r->code-1, r->af);
697 if (ic != NULL)
698 printf(" code %s", ic->name);
699 else
700 printf(" code %u", r->code-1);
701 }
702 }
703 if (r->tos)
704 printf(" tos 0x%2.2x", r->tos);
705 if (r->keep_state == PF_STATE_NORMAL)
706 printf(" keep state");
707 else if (r->keep_state == PF_STATE_MODULATE)
708 printf(" modulate state");
709 else if (r->keep_state == PF_STATE_SYNPROXY)
710 printf(" synproxy state");
711 opts = 0;
712 if (r->max_states)
713 opts = 1;
714 for (i = 0; !opts && i < PFTM_MAX; ++i)
715 if (r->timeout[i])
716 opts = 1;
717 if (opts) {
718 printf(" (");
719 if (r->max_states) {
720 printf("max %u", r->max_states);
721 opts = 0;
722 }
723 for (i = 0; i < PFTM_MAX; ++i)
724 if (r->timeout[i]) {
725 if (!opts)
726 printf(", ");
727 opts = 0;
728 printf("%s %u", pf_timeouts[i].name,
729 r->timeout[i]);
730 }
731 printf(")");
732 }
733 if (r->rule_flag & PFRULE_FRAGMENT)
734 printf(" fragment");
735 if (r->rule_flag & PFRULE_NODF)
736 printf(" no-df");
737 if (r->rule_flag & PFRULE_RANDOMID)
738 printf(" random-id");
739 if (r->min_ttl)
740 printf(" min-ttl %d", r->min_ttl);
741 if (r->max_mss)
742 printf(" max-mss %d", r->max_mss);
743 if (r->allow_opts)
744 printf(" allow-opts");
745 if (r->action == PF_SCRUB) {
746 if (r->rule_flag & PFRULE_REASSEMBLE_TCP)
747 printf(" reassemble tcp");
748
749 if (r->rule_flag & PFRULE_FRAGDROP)
750 printf(" fragment drop-ovl");
751 else if (r->rule_flag & PFRULE_FRAGCROP)
752 printf(" fragment crop");
753 else
754 printf(" fragment reassemble");
755 }
756 if (r->label[0])
757 printf(" label \"%s\"", r->label);
758 if (r->qname[0] && r->pqname[0])
759 printf(" queue(%s, %s)", r->qname, r->pqname);
760 else if (r->qname[0])
761 printf(" queue %s", r->qname);
762 if (r->tagname[0])
763 printf(" tag %s", r->tagname);
764 if (r->match_tagname[0]) {
765 if (r->match_tag_not)
766 printf(" !");
767 printf(" tagged %s", r->match_tagname);
768 }
769 if (!r->anchorname[0] && (r->action == PF_NAT ||
770 r->action == PF_BINAT || r->action == PF_RDR)) {
771 printf(" -> ");
772 print_pool(&r->rpool, r->rpool.proxy_port[0],
773 r->rpool.proxy_port[1], r->af, r->action);
774 }
775 printf("\n");
776}
777
778void
779print_tabledef(const char *name, int flags, int addrs,
780 struct node_tinithead *nodes)
781{
782 struct node_tinit *ti, *nti;
783 struct node_host *h;
784
785 printf("table <%s>", name);
786 if (flags & PFR_TFLAG_CONST)
787 printf(" const");
788 if (flags & PFR_TFLAG_PERSIST)
789 printf(" persist");
790 SIMPLEQ_FOREACH(ti, nodes, entries) {
791 if (ti->file) {
792 printf(" file \"%s\"", ti->file);
793 continue;
794 }
795 printf(" {");
796 for (;;) {
797 for (h = ti->host; h != NULL; h = h->next) {
798 printf(h->not ? " !" : " ");
799 print_addr(&h->addr, h->af, 0);
800 }
801 nti = SIMPLEQ_NEXT(ti, entries);
802 if (nti != NULL && nti->file == NULL)
803 ti = nti; /* merge lists */
804 else
805 break;
806 }
807 printf(" }");
808 }
809 if (addrs && SIMPLEQ_EMPTY(nodes))
810 printf(" { }");
811 printf("\n");
812}
813
814int
815parse_flags(char *s)
816{
817 char *p, *q;
818 u_int8_t f = 0;
819
820 for (p = s; *p; p++) {
821 if ((q = strchr(tcpflags, *p)) == NULL)
822 return -1;
823 else
824 f |= 1 << (q - tcpflags);
825 }
826 return (f ? f : PF_TH_ALL);
827}
828
829void
830set_ipmask(struct node_host *h, u_int8_t b)
831{
832 struct pf_addr *m, *n;
833 int i, j = 0;
834
835 m = &h->addr.v.a.mask;
836
837 for (i = 0; i < 4; i++)
838 m->addr32[i] = 0;
839
840 while (b >= 32) {
841 m->addr32[j++] = 0xffffffff;
842 b -= 32;
843 }
844 for (i = 31; i > 31-b; --i)
845 m->addr32[j] |= (1 << i);
846 if (b)
847 m->addr32[j] = htonl(m->addr32[j]);
848
849 /* Mask off bits of the address that will never be used. */
850 n = &h->addr.v.a.addr;
851 if (h->addr.type == PF_ADDR_ADDRMASK)
852 for (i = 0; i < 4; i++)
853 n->addr32[i] = n->addr32[i] & m->addr32[i];
854}
855
856int
857check_netmask(struct node_host *h, sa_family_t af)
858{
859 struct node_host *n = NULL;
860 struct pf_addr *m;
861
862 for (n = h; n != NULL; n = n->next) {
863 if (h->addr.type == PF_ADDR_TABLE)
864 continue;
865 m = &h->addr.v.a.mask;
866 /* fix up netmask for dynaddr */
867 if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL &&
868 unmask(m, AF_INET6) > 32)
869 set_ipmask(n, 32);
870 /* netmasks > 32 bit are invalid on v4 */
871 if (af == AF_INET &&
872 (m->addr32[1] || m->addr32[2] || m->addr32[3])) {
873 fprintf(stderr, "netmask %u invalid for IPv4 address\n",
874 unmask(m, AF_INET6));
875 return (1);
876 }
877 }
878 return (0);
879}
880
881/* interface lookup routines */
882
883struct node_host *iftab;
884
885void
886ifa_load(void)
887{
888 struct ifaddrs *ifap, *ifa;
889 struct node_host *n = NULL, *h = NULL;
890
891 if (getifaddrs(&ifap) < 0)
892 err(1, "getifaddrs");
893
894 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
895 if (!(ifa->ifa_addr->sa_family == AF_INET ||
896 ifa->ifa_addr->sa_family == AF_INET6 ||
897 ifa->ifa_addr->sa_family == AF_LINK))
898 continue;
899 n = calloc(1, sizeof(struct node_host));
900 if (n == NULL)
901 err(1, "address: calloc");
902 n->af = ifa->ifa_addr->sa_family;
903 n->ifa_flags = ifa->ifa_flags;
904#ifdef __KAME__
905 if (n->af == AF_INET6 &&
906 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)
907 ifa->ifa_addr)->sin6_addr) &&
908 ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) {
909 struct sockaddr_in6 *sin6;
910
911 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
912 sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
913 sin6->sin6_addr.s6_addr[3];
914 sin6->sin6_addr.s6_addr[2] = 0;
915 sin6->sin6_addr.s6_addr[3] = 0;
916 }
917#endif
918 n->ifindex = 0;
919 if (n->af == AF_INET) {
920 memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *)
921 ifa->ifa_addr)->sin_addr.s_addr,
922 sizeof(struct in_addr));
923 memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *)
924 ifa->ifa_netmask)->sin_addr.s_addr,
925 sizeof(struct in_addr));
926 if (ifa->ifa_broadaddr != NULL)
927 memcpy(&n->bcast, &((struct sockaddr_in *)
928 ifa->ifa_broadaddr)->sin_addr.s_addr,
929 sizeof(struct in_addr));
930 } else if (n->af == AF_INET6) {
931 memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *)
932 ifa->ifa_addr)->sin6_addr.s6_addr,
933 sizeof(struct in6_addr));
934 memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *)
935 ifa->ifa_netmask)->sin6_addr.s6_addr,
936 sizeof(struct in6_addr));
937 if (ifa->ifa_broadaddr != NULL)
938 memcpy(&n->bcast, &((struct sockaddr_in6 *)
939 ifa->ifa_broadaddr)->sin6_addr.s6_addr,
940 sizeof(struct in6_addr));
941 n->ifindex = ((struct sockaddr_in6 *)
942 ifa->ifa_addr)->sin6_scope_id;
943 }
944 if ((n->ifname = strdup(ifa->ifa_name)) == NULL)
945 err(1, "ifa_load: strdup");
946 n->next = NULL;
947 n->tail = n;
948 if (h == NULL)
949 h = n;
950 else {
951 h->tail->next = n;
952 h->tail = n;
953 }
954 }
955 iftab = h;
956 freeifaddrs(ifap);
957}
958
959struct node_host *
960ifa_exists(const char *ifa_name)
961{
962 struct node_host *n;
963
964 if (iftab == NULL)
965 ifa_load();
966
967 for (n = iftab; n; n = n->next) {
968 if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
969 return (n);
970 }
971 return (NULL);
972}
973
974struct node_host *
975ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode)
976{
977 struct node_host *p = NULL, *h = NULL, *n = NULL;
978 int return_all = 0;
979
980 if (!strncmp(ifa_name, "self", IFNAMSIZ))
981 return_all = 1;
982
983 if (iftab == NULL)
984 ifa_load();
985
986 for (p = iftab; p; p = p->next) {
987 if (!((p->af == AF_INET || p->af == AF_INET6) &&
988 (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all)))
989 continue;
990 if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
991 continue;
992 if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
993 continue;
994 n = calloc(1, sizeof(struct node_host));
995 if (n == NULL)
996 err(1, "address: calloc");
997 n->af = p->af;
998 if (mode == PFCTL_IFLOOKUP_BCAST)
999 memcpy(&n->addr.v.a.addr, &p->bcast,
1000 sizeof(struct pf_addr));
1001 else
1002 memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr,
1003 sizeof(struct pf_addr));
1004 if (mode == PFCTL_IFLOOKUP_NET)
1005 set_ipmask(n, unmask(&p->addr.v.a.mask, n->af));
1006 else {
1007 if (n->af == AF_INET) {
1008 if (p->ifa_flags & IFF_LOOPBACK &&
1009 p->ifa_flags & IFF_LINK1)
1010 memcpy(&n->addr.v.a.mask,
1011 &p->addr.v.a.mask,
1012 sizeof(struct pf_addr));
1013 else
1014 set_ipmask(n, 32);
1015 } else
1016 set_ipmask(n, 128);
1017 }
1018 n->ifindex = p->ifindex;
1019
1020 n->next = NULL;
1021 n->tail = n;
1022 if (h == NULL)
1023 h = n;
1024 else {
1025 h->tail->next = n;
1026 h->tail = n;
1027 }
1028 }
1029 if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) {
1030 fprintf(stderr, "no IP address found for %s\n", ifa_name);
1031 }
1032 return (h);
1033}
1034
1035struct node_host *
1036host(const char *s)
1037{
1038 struct node_host *h = NULL;
1039 int mask, v4mask, v6mask, cont = 1;
1040 char *p, *q, *ps;
1041
1042 if ((p = strrchr(s, '/')) != NULL) {
1043 mask = strtol(p+1, &q, 0);
1044 if (!q || *q || mask > 128 || q == (p+1)) {
1045 fprintf(stderr, "invalid netmask\n");
1046 return (NULL);
1047 }
1048 if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
1049 err(1, "host: malloc");
1050 strlcpy(ps, s, strlen(s) - strlen(p) + 1);
1051 v4mask = v6mask = mask;
1052 } else {
1053 if ((ps = strdup(s)) == NULL)
1054 err(1, "host: strdup");
1055 v4mask = 32;
1056 v6mask = 128;
1057 mask = -1;
1058 }
1059
1060 /* interface with this name exists? */
1061 if (cont && (h = host_if(ps, mask)) != NULL)
1062 cont = 0;
1063
1064 /* IPv4 address? */
1065 if (cont && (h = host_v4(s, mask)) != NULL)
1066 cont = 0;
1067
1068 /* IPv6 address? */
1069 if (cont && (h = host_v6(ps, v6mask)) != NULL)
1070 cont = 0;
1071
1072 /* dns lookup */
1073 if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL)
1074 cont = 0;
1075 free(ps);
1076
1077 if (h == NULL || cont == 1) {
1078 fprintf(stderr, "no IP address found for %s\n", s);
1079 return (NULL);
1080 }
1081 return (h);
1082}
1083
1084struct node_host *
1085host_if(const char *s, int mask)
1086{
1087 struct node_host *n, *h = NULL;
1088 char *p, *ps;
1089 int mode = PFCTL_IFLOOKUP_HOST;
1090
1091 if ((p = strrchr(s, ':')) != NULL &&
1092 (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) {
1093 if (!strcmp(p+1, "network"))
1094 mode = PFCTL_IFLOOKUP_NET;
1095 if (!strcmp(p+1, "broadcast"))
1096 mode = PFCTL_IFLOOKUP_BCAST;
1097 if (mask > -1) {
1098 fprintf(stderr, "network or broadcast lookup, but "
1099 "extra netmask given\n");
1100 return (NULL);
1101 }
1102 if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
1103 err(1, "host: malloc");
1104 strlcpy(ps, s, strlen(s) - strlen(p) + 1);
1105 } else
1106 if ((ps = strdup(s)) == NULL)
1107 err(1, "host_if: strdup");
1108
1109 if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
1110 /* interface with this name exists */
1111 h = ifa_lookup(ps, mode);
1112 for (n = h; n != NULL && mask > -1; n = n->next)
1113 set_ipmask(n, mask);
1114 }
1115
1116 free(ps);
1117 return (h);
1118}
1119
1120struct node_host *
1121host_v4(const char *s, int mask)
1122{
1123 struct node_host *h = NULL;
1124 struct in_addr ina;
1125 int bits;
1126
1127 memset(&ina, 0, sizeof(struct in_addr));
1128 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) > -1) {
1129 h = calloc(1, sizeof(struct node_host));
1130 if (h == NULL)
1131 err(1, "address: calloc");
1132 h->ifname = NULL;
1133 h->af = AF_INET;
1134 h->addr.v.a.addr.addr32[0] = ina.s_addr;
1135#if defined(__FreeBSD__) && (__FreeBSD_version <= 501106)
1136 /* inet_net_pton acts strange w/ multicast addresses, RFC1112 */
1137 if (mask == -1 && h->addr.v.a.addr.addr8[0] >= 224 &&
1138 h->addr.v.a.addr.addr8[0] < 240)
1139 bits = 32;
1140#endif
1127 set_ipmask(h, bits);
1128 h->next = NULL;
1129 h->tail = h;
1130 }
1131
1132 return (h);
1133}
1134
1135struct node_host *
1136host_v6(const char *s, int mask)
1137{
1138 struct addrinfo hints, *res;
1139 struct node_host *h = NULL;
1140
1141 memset(&hints, 0, sizeof(hints));
1142 hints.ai_family = AF_INET6;
1143 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
1144 hints.ai_flags = AI_NUMERICHOST;
1145 if (getaddrinfo(s, "0", &hints, &res) == 0) {
1146 h = calloc(1, sizeof(struct node_host));
1147 if (h == NULL)
1148 err(1, "address: calloc");
1149 h->ifname = NULL;
1150 h->af = AF_INET6;
1151 memcpy(&h->addr.v.a.addr,
1152 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1153 sizeof(h->addr.v.a.addr));
1154 h->ifindex =
1155 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
1156 set_ipmask(h, mask);
1157 freeaddrinfo(res);
1158 h->next = NULL;
1159 h->tail = h;
1160 }
1161
1162 return (h);
1163}
1164
1165struct node_host *
1166host_dns(const char *s, int v4mask, int v6mask)
1167{
1168 struct addrinfo hints, *res0, *res;
1169 struct node_host *n, *h = NULL;
1170 int error;
1171
1172 memset(&hints, 0, sizeof(hints));
1173 hints.ai_family = PF_UNSPEC;
1174 hints.ai_socktype = SOCK_STREAM; /* DUMMY */
1175 error = getaddrinfo(s, NULL, &hints, &res0);
1176 if (error)
1177 return (h);
1178
1179 for (res = res0; res; res = res->ai_next) {
1180 if (res->ai_family != AF_INET &&
1181 res->ai_family != AF_INET6)
1182 continue;
1183 n = calloc(1, sizeof(struct node_host));
1184 if (n == NULL)
1185 err(1, "host_dns: calloc");
1186 n->ifname = NULL;
1187 n->af = res->ai_family;
1188 if (res->ai_family == AF_INET) {
1189 memcpy(&n->addr.v.a.addr,
1190 &((struct sockaddr_in *)
1191 res->ai_addr)->sin_addr.s_addr,
1192 sizeof(struct in_addr));
1193 set_ipmask(n, v4mask);
1194 } else {
1195 memcpy(&n->addr.v.a.addr,
1196 &((struct sockaddr_in6 *)
1197 res->ai_addr)->sin6_addr.s6_addr,
1198 sizeof(struct in6_addr));
1199 n->ifindex =
1200 ((struct sockaddr_in6 *)
1201 res->ai_addr)->sin6_scope_id;
1202 set_ipmask(n, v6mask);
1203 }
1204 n->next = NULL;
1205 n->tail = n;
1206 if (h == NULL)
1207 h = n;
1208 else {
1209 h->tail->next = n;
1210 h->tail = n;
1211 }
1212 }
1213 freeaddrinfo(res0);
1214
1215 return (h);
1216}
1217
1218/*
1219 * convert a hostname to a list of addresses and put them in the given buffer.
1220 * test:
1221 * if set to 1, only simple addresses are accepted (no netblock, no "!").
1222 */
1223int
1224append_addr(struct pfr_buffer *b, char *s, int test)
1225{
1226 char *r;
1227 struct node_host *h, *n;
1228 int rv, not = 0;
1229
1230 for (r = s; *r == '!'; r++)
1231 not = !not;
1232 if ((n = host(r)) == NULL) {
1233 errno = 0;
1234 return (-1);
1235 }
1236 rv = append_addr_host(b, n, test, not);
1237 do {
1238 h = n;
1239 n = n->next;
1240 free(h);
1241 } while (n != NULL);
1242 return (rv);
1243}
1244
1245/*
1246 * same as previous function, but with a pre-parsed input and the ability
1247 * to "negate" the result. Does not free the node_host list.
1248 * not:
1249 * setting it to 1 is equivalent to adding "!" in front of parameter s.
1250 */
1251int
1252append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not)
1253{
1254 int bits;
1255 struct pfr_addr addr;
1256
1257 do {
1258 bzero(&addr, sizeof(addr));
1259 addr.pfra_not = n->not ^ not;
1260 addr.pfra_af = n->af;
1261 addr.pfra_net = unmask(&n->addr.v.a.mask, n->af);
1262 switch (n->af) {
1263 case AF_INET:
1264 addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0];
1265 bits = 32;
1266 break;
1267 case AF_INET6:
1268 memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6,
1269 sizeof(struct in6_addr));
1270 bits = 128;
1271 break;
1272 default:
1273 errno = EINVAL;
1274 return (-1);
1275 }
1276 if ((test && (not || addr.pfra_net != bits)) ||
1277 addr.pfra_net > bits) {
1278 errno = EINVAL;
1279 return (-1);
1280 }
1281 if (pfr_buf_add(b, &addr))
1282 return (-1);
1283 } while ((n = n->next) != NULL);
1284
1285 return (0);
1286}
1141 set_ipmask(h, bits);
1142 h->next = NULL;
1143 h->tail = h;
1144 }
1145
1146 return (h);
1147}
1148
1149struct node_host *
1150host_v6(const char *s, int mask)
1151{
1152 struct addrinfo hints, *res;
1153 struct node_host *h = NULL;
1154
1155 memset(&hints, 0, sizeof(hints));
1156 hints.ai_family = AF_INET6;
1157 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
1158 hints.ai_flags = AI_NUMERICHOST;
1159 if (getaddrinfo(s, "0", &hints, &res) == 0) {
1160 h = calloc(1, sizeof(struct node_host));
1161 if (h == NULL)
1162 err(1, "address: calloc");
1163 h->ifname = NULL;
1164 h->af = AF_INET6;
1165 memcpy(&h->addr.v.a.addr,
1166 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1167 sizeof(h->addr.v.a.addr));
1168 h->ifindex =
1169 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
1170 set_ipmask(h, mask);
1171 freeaddrinfo(res);
1172 h->next = NULL;
1173 h->tail = h;
1174 }
1175
1176 return (h);
1177}
1178
1179struct node_host *
1180host_dns(const char *s, int v4mask, int v6mask)
1181{
1182 struct addrinfo hints, *res0, *res;
1183 struct node_host *n, *h = NULL;
1184 int error;
1185
1186 memset(&hints, 0, sizeof(hints));
1187 hints.ai_family = PF_UNSPEC;
1188 hints.ai_socktype = SOCK_STREAM; /* DUMMY */
1189 error = getaddrinfo(s, NULL, &hints, &res0);
1190 if (error)
1191 return (h);
1192
1193 for (res = res0; res; res = res->ai_next) {
1194 if (res->ai_family != AF_INET &&
1195 res->ai_family != AF_INET6)
1196 continue;
1197 n = calloc(1, sizeof(struct node_host));
1198 if (n == NULL)
1199 err(1, "host_dns: calloc");
1200 n->ifname = NULL;
1201 n->af = res->ai_family;
1202 if (res->ai_family == AF_INET) {
1203 memcpy(&n->addr.v.a.addr,
1204 &((struct sockaddr_in *)
1205 res->ai_addr)->sin_addr.s_addr,
1206 sizeof(struct in_addr));
1207 set_ipmask(n, v4mask);
1208 } else {
1209 memcpy(&n->addr.v.a.addr,
1210 &((struct sockaddr_in6 *)
1211 res->ai_addr)->sin6_addr.s6_addr,
1212 sizeof(struct in6_addr));
1213 n->ifindex =
1214 ((struct sockaddr_in6 *)
1215 res->ai_addr)->sin6_scope_id;
1216 set_ipmask(n, v6mask);
1217 }
1218 n->next = NULL;
1219 n->tail = n;
1220 if (h == NULL)
1221 h = n;
1222 else {
1223 h->tail->next = n;
1224 h->tail = n;
1225 }
1226 }
1227 freeaddrinfo(res0);
1228
1229 return (h);
1230}
1231
1232/*
1233 * convert a hostname to a list of addresses and put them in the given buffer.
1234 * test:
1235 * if set to 1, only simple addresses are accepted (no netblock, no "!").
1236 */
1237int
1238append_addr(struct pfr_buffer *b, char *s, int test)
1239{
1240 char *r;
1241 struct node_host *h, *n;
1242 int rv, not = 0;
1243
1244 for (r = s; *r == '!'; r++)
1245 not = !not;
1246 if ((n = host(r)) == NULL) {
1247 errno = 0;
1248 return (-1);
1249 }
1250 rv = append_addr_host(b, n, test, not);
1251 do {
1252 h = n;
1253 n = n->next;
1254 free(h);
1255 } while (n != NULL);
1256 return (rv);
1257}
1258
1259/*
1260 * same as previous function, but with a pre-parsed input and the ability
1261 * to "negate" the result. Does not free the node_host list.
1262 * not:
1263 * setting it to 1 is equivalent to adding "!" in front of parameter s.
1264 */
1265int
1266append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not)
1267{
1268 int bits;
1269 struct pfr_addr addr;
1270
1271 do {
1272 bzero(&addr, sizeof(addr));
1273 addr.pfra_not = n->not ^ not;
1274 addr.pfra_af = n->af;
1275 addr.pfra_net = unmask(&n->addr.v.a.mask, n->af);
1276 switch (n->af) {
1277 case AF_INET:
1278 addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0];
1279 bits = 32;
1280 break;
1281 case AF_INET6:
1282 memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6,
1283 sizeof(struct in6_addr));
1284 bits = 128;
1285 break;
1286 default:
1287 errno = EINVAL;
1288 return (-1);
1289 }
1290 if ((test && (not || addr.pfra_net != bits)) ||
1291 addr.pfra_net > bits) {
1292 errno = EINVAL;
1293 return (-1);
1294 }
1295 if (pfr_buf_add(b, &addr))
1296 return (-1);
1297 } while ((n = n->next) != NULL);
1298
1299 return (0);
1300}