1 /* $OpenBSD: pfctl_parser.c,v 1.172 2003/07/29 19:47:22 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 54 #include "pfctl_parser.h" 55 #include "pfctl.h" 56 57 void print_op (u_int8_t, const char *, const char *); 58 void print_port (u_int8_t, u_int16_t, u_int16_t, const char *); 59 void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); 60 void print_flags (u_int8_t); 61 void print_fromto(struct pf_rule_addr *, struct pf_rule_addr *, 62 u_int8_t, u_int8_t, int); 63 64 struct node_host *host_if(const char *, int); 65 struct node_host *host_v4(const char *, int); 66 struct node_host *host_v6(const char *, int); 67 struct node_host *host_dns(const char *, int, int); 68 69 const char *tcpflags = "FSRPAUEW"; 70 71 static 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 99 static 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 128 static 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 161 static 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 176 const 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 198 const struct icmptypeent * 199 geticmptypebynumber(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 219 const struct icmptypeent * 220 geticmptypebyname(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 240 const struct icmpcodeent * 241 geticmpcodebynumber(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 263 const struct icmpcodeent * 264 geticmpcodebyname(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 286 void 287 print_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 309 void 310 print_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 327 void 328 print_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 341 void 342 print_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 351 void 352 print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst, 353 sa_family_t af, u_int8_t proto, int verbose) 354 { 355 if (src->addr.type == PF_ADDR_ADDRMASK && 356 dst->addr.type == PF_ADDR_ADDRMASK && 357 PF_AZERO(&src->addr.v.a.addr, AF_INET6) && 358 PF_AZERO(&src->addr.v.a.mask, AF_INET6) && 359 PF_AZERO(&dst->addr.v.a.addr, AF_INET6) && 360 PF_AZERO(&dst->addr.v.a.mask, AF_INET6) && 361 !src->not && !dst->not && 362 !src->port_op && !dst->port_op) 363 printf(" all"); 364 else { 365 printf(" from "); 366 if (src->not) 367 printf("! "); 368 print_addr(&src->addr, af, verbose); 369 if (src->port_op) 370 print_port(src->port_op, src->port[0], 371 src->port[1], 372 proto == IPPROTO_TCP ? "tcp" : "udp"); 373 374 printf(" to "); 375 if (dst->not) 376 printf("! "); 377 print_addr(&dst->addr, af, verbose); 378 if (dst->port_op) 379 print_port(dst->port_op, dst->port[0], 380 dst->port[1], 381 proto == IPPROTO_TCP ? "tcp" : "udp"); 382 } 383 } 384 385 void 386 print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, 387 sa_family_t af, int id) 388 { 389 struct pf_pooladdr *pooladdr; 390 391 if ((TAILQ_FIRST(&pool->list) != NULL) && 392 TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) 393 printf("{ "); 394 TAILQ_FOREACH(pooladdr, &pool->list, entries){ 395 switch (id) { 396 case PF_NAT: 397 case PF_RDR: 398 case PF_BINAT: 399 print_addr(&pooladdr->addr, af, 0); 400 break; 401 case PF_PASS: 402 if (PF_AZERO(&pooladdr->addr.v.a.addr, af)) 403 printf("%s", pooladdr->ifname); 404 else { 405 printf("(%s ", pooladdr->ifname); 406 print_addr(&pooladdr->addr, af, 0); 407 printf(")"); 408 } 409 break; 410 default: 411 break; 412 } 413 if (TAILQ_NEXT(pooladdr, entries) != NULL) 414 printf(", "); 415 else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) 416 printf(" }"); 417 } 418 switch (id) { 419 case PF_NAT: 420 if ((p1 != PF_NAT_PROXY_PORT_LOW || 421 p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) { 422 if (p1 == p2) 423 printf(" port %u", p1); 424 else 425 printf(" port %u:%u", p1, p2); 426 } 427 break; 428 case PF_RDR: 429 if (p1) { 430 printf(" port %u", p1); 431 if (p2 && (p2 != p1)) 432 printf(":%u", p2); 433 } 434 break; 435 default: 436 break; 437 } 438 switch (pool->opts & PF_POOL_TYPEMASK) { 439 case PF_POOL_NONE: 440 break; 441 case PF_POOL_BITMASK: 442 printf(" bitmask"); 443 break; 444 case PF_POOL_RANDOM: 445 printf(" random"); 446 break; 447 case PF_POOL_SRCHASH: 448 printf(" source-hash 0x%08x%08x%08x%08x", 449 pool->key.key32[0], pool->key.key32[1], 450 pool->key.key32[2], pool->key.key32[3]); 451 break; 452 case PF_POOL_ROUNDROBIN: 453 printf(" round-robin"); 454 break; 455 } 456 if (id == PF_NAT && p1 == 0 && p2 == 0) 457 printf(" static-port"); 458 } 459 460 const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; 461 const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; 462 463 void 464 print_status(struct pf_status *s) 465 { 466 char statline[80]; 467 time_t runtime; 468 int i; 469 470 runtime = time(NULL) - s->since; 471 472 if (s->running) { 473 unsigned sec, min, hrs, day = runtime; 474 475 sec = day % 60; 476 day /= 60; 477 min = day % 60; 478 day /= 60; 479 hrs = day % 24; 480 day /= 24; 481 snprintf(statline, sizeof(statline), 482 "Status: Enabled for %u days %.2u:%.2u:%.2u", 483 day, hrs, min, sec); 484 } else 485 snprintf(statline, sizeof(statline), "Status: Disabled"); 486 printf("%-44s", statline); 487 switch (s->debug) { 488 case 0: 489 printf("%15s\n\n", "Debug: None"); 490 break; 491 case 1: 492 printf("%15s\n\n", "Debug: Urgent"); 493 break; 494 case 2: 495 printf("%15s\n\n", "Debug: Misc"); 496 break; 497 } 498 if (s->ifname[0] != 0) { 499 printf("Interface Stats for %-16s %5s %16s\n", 500 s->ifname, "IPv4", "IPv6"); 501 printf(" %-25s %14llu %16llu\n", "Bytes In", 502 s->bcounters[0][0], s->bcounters[1][0]); 503 printf(" %-25s %14llu %16llu\n", "Bytes Out", 504 s->bcounters[0][1], s->bcounters[1][1]); 505 printf(" Packets In\n"); 506 printf(" %-23s %14llu %16llu\n", "Passed", 507 s->pcounters[0][0][PF_PASS], 508 s->pcounters[1][0][PF_PASS]); 509 printf(" %-23s %14llu %16llu\n", "Blocked", 510 s->pcounters[0][0][PF_DROP], 511 s->pcounters[1][0][PF_DROP]); 512 printf(" Packets Out\n"); 513 printf(" %-23s %14llu %16llu\n", "Passed", 514 s->pcounters[0][1][PF_PASS], 515 s->pcounters[1][1][PF_PASS]); 516 printf(" %-23s %14llu %16llu\n\n", "Blocked", 517 s->pcounters[0][1][PF_DROP], 518 s->pcounters[1][1][PF_DROP]); 519 } 520 printf("%-27s %14s %16s\n", "State Table", "Total", "Rate"); 521 printf(" %-25s %14u %14s\n", "current entries", s->states, ""); 522 for (i = 0; i < FCNT_MAX; i++) { 523 printf(" %-25s %14lld ", pf_fcounters[i], 524 s->fcounters[i]); 525 if (runtime > 0) 526 printf("%14.1f/s\n", 527 (double)s->fcounters[i] / (double)runtime); 528 else 529 printf("%14s\n", ""); 530 } 531 printf("Counters\n"); 532 for (i = 0; i < PFRES_MAX; i++) { 533 printf(" %-25s %14lld ", pf_reasons[i], 534 s->counters[i]); 535 if (runtime > 0) 536 printf("%14.1f/s\n", 537 (double)s->counters[i] / (double)runtime); 538 else 539 printf("%14s\n", ""); 540 } 541 } 542 543 void 544 print_rule(struct pf_rule *r, int verbose) 545 { 546 static const char *actiontypes[] = { "pass", "block", "scrub", "nat", 547 "no nat", "binat", "no binat", "rdr", "no rdr" }; 548 static const char *anchortypes[] = { "anchor", "anchor", "anchor", 549 "nat-anchor", "nat-anchor", "binat-anchor", "binat-anchor", 550 "rdr-anchor", "rdr-anchor" }; 551 int i, opts; 552 553 if (verbose) 554 printf("@%d ", r->nr); 555 if (r->action > PF_NORDR) 556 printf("action(%d)", r->action); 557 else if (r->anchorname[0]) 558 printf("%s %s", anchortypes[r->action], r->anchorname); 559 else { 560 printf("%s", actiontypes[r->action]); 561 if (r->natpass) 562 printf(" pass"); 563 } 564 if (r->action == PF_DROP) { 565 if (r->rule_flag & PFRULE_RETURN) 566 printf(" return"); 567 else if (r->rule_flag & PFRULE_RETURNRST) { 568 if (!r->return_ttl) 569 printf(" return-rst"); 570 else 571 printf(" return-rst(ttl %d)", r->return_ttl); 572 } else if (r->rule_flag & PFRULE_RETURNICMP) { 573 const struct icmpcodeent *ic, *ic6; 574 575 ic = geticmpcodebynumber(r->return_icmp >> 8, 576 r->return_icmp & 255, AF_INET); 577 ic6 = geticmpcodebynumber(r->return_icmp6 >> 8, 578 r->return_icmp6 & 255, AF_INET6); 579 580 switch(r->af) { 581 case AF_INET: 582 printf(" return-icmp"); 583 if (ic == NULL) 584 printf("(%u)", r->return_icmp & 255); 585 else 586 printf("(%s)", ic->name); 587 break; 588 case AF_INET6: 589 printf(" return-icmp6"); 590 if (ic6 == NULL) 591 printf("(%u)", r->return_icmp6 & 255); 592 else 593 printf("(%s)", ic6->name); 594 break; 595 default: 596 printf(" return-icmp"); 597 if (ic == NULL) 598 printf("(%u, ", r->return_icmp & 255); 599 else 600 printf("(%s, ", ic->name); 601 if (ic6 == NULL) 602 printf("%u)", r->return_icmp6 & 255); 603 else 604 printf("%s)", ic6->name); 605 break; 606 } 607 } else 608 printf(" drop"); 609 } 610 if (r->direction == PF_IN) 611 printf(" in"); 612 else if (r->direction == PF_OUT) 613 printf(" out"); 614 if (r->log == 1) 615 printf(" log"); 616 else if (r->log == 2) 617 printf(" log-all"); 618 if (r->quick) 619 printf(" quick"); 620 if (r->ifname[0]) { 621 if (r->ifnot) 622 printf(" on ! %s", r->ifname); 623 else 624 printf(" on %s", r->ifname); 625 } 626 if (r->rt) { 627 if (r->rt == PF_ROUTETO) 628 printf(" route-to"); 629 else if (r->rt == PF_REPLYTO) 630 printf(" reply-to"); 631 else if (r->rt == PF_DUPTO) 632 printf(" dup-to"); 633 else if (r->rt == PF_FASTROUTE) 634 printf(" fastroute"); 635 if (r->rt != PF_FASTROUTE) { 636 printf(" "); 637 print_pool(&r->rpool, 0, 0, r->af, PF_PASS); 638 } 639 } 640 if (r->af) { 641 if (r->af == AF_INET) 642 printf(" inet"); 643 else 644 printf(" inet6"); 645 } 646 if (r->proto) { 647 struct protoent *p; 648 649 if ((p = getprotobynumber(r->proto)) != NULL) 650 printf(" proto %s", p->p_name); 651 else 652 printf(" proto %u", r->proto); 653 } 654 print_fromto(&r->src, &r->dst, r->af, r->proto, verbose); 655 if (r->uid.op) 656 print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", 657 UID_MAX); 658 if (r->gid.op) 659 print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", 660 GID_MAX); 661 if (r->flags || r->flagset) { 662 printf(" flags "); 663 print_flags(r->flags); 664 printf("/"); 665 print_flags(r->flagset); 666 } 667 if (r->type) { 668 const struct icmptypeent *it; 669 670 it = geticmptypebynumber(r->type-1, r->af); 671 if (r->af != AF_INET6) 672 printf(" icmp-type"); 673 else 674 printf(" icmp6-type"); 675 if (it != NULL) 676 printf(" %s", it->name); 677 else 678 printf(" %u", r->type-1); 679 if (r->code) { 680 const struct icmpcodeent *ic; 681 682 ic = geticmpcodebynumber(r->type-1, r->code-1, r->af); 683 if (ic != NULL) 684 printf(" code %s", ic->name); 685 else 686 printf(" code %u", r->code-1); 687 } 688 } 689 if (r->tos) 690 printf(" tos 0x%2.2x", r->tos); 691 if (r->keep_state == PF_STATE_NORMAL) 692 printf(" keep state"); 693 else if (r->keep_state == PF_STATE_MODULATE) 694 printf(" modulate state"); 695 else if (r->keep_state == PF_STATE_SYNPROXY) 696 printf(" synproxy state"); 697 opts = 0; 698 if (r->max_states) 699 opts = 1; 700 for (i = 0; !opts && i < PFTM_MAX; ++i) 701 if (r->timeout[i]) 702 opts = 1; 703 if (opts) { 704 printf(" ("); 705 if (r->max_states) { 706 printf("max %u", r->max_states); 707 opts = 0; 708 } 709 for (i = 0; i < PFTM_MAX; ++i) 710 if (r->timeout[i]) { 711 if (!opts) 712 printf(", "); 713 opts = 0; 714 printf("%s %u", pf_timeouts[i].name, 715 r->timeout[i]); 716 } 717 printf(")"); 718 } 719 if (r->rule_flag & PFRULE_FRAGMENT) 720 printf(" fragment"); 721 if (r->rule_flag & PFRULE_NODF) 722 printf(" no-df"); 723 if (r->rule_flag & PFRULE_RANDOMID) 724 printf(" random-id"); 725 if (r->min_ttl) 726 printf(" min-ttl %d", r->min_ttl); 727 if (r->max_mss) 728 printf(" max-mss %d", r->max_mss); 729 if (r->allow_opts) 730 printf(" allow-opts"); 731 if (r->action == PF_SCRUB) { 732 if (r->rule_flag & PFRULE_REASSEMBLE_TCP) 733 printf(" reassemble tcp"); 734 735 if (r->rule_flag & PFRULE_FRAGDROP) 736 printf(" fragment drop-ovl"); 737 else if (r->rule_flag & PFRULE_FRAGCROP) 738 printf(" fragment crop"); 739 else 740 printf(" fragment reassemble"); 741 } 742 if (r->label[0]) 743 printf(" label \"%s\"", r->label); 744 if (r->qname[0] && r->pqname[0]) 745 printf(" queue(%s, %s)", r->qname, r->pqname); 746 else if (r->qname[0]) 747 printf(" queue %s", r->qname); 748 if (r->tagname[0]) 749 printf(" tag %s", r->tagname); 750 if (r->match_tagname[0]) { 751 if (r->match_tag_not) 752 printf(" !"); 753 printf(" tagged %s", r->match_tagname); 754 } 755 if (!r->anchorname[0] && (r->action == PF_NAT || 756 r->action == PF_BINAT || r->action == PF_RDR)) { 757 printf(" -> "); 758 print_pool(&r->rpool, r->rpool.proxy_port[0], 759 r->rpool.proxy_port[1], r->af, r->action); 760 } 761 printf("\n"); 762 } 763 764 void 765 print_tabledef(const char *name, int flags, int addrs, 766 struct node_tinithead *nodes) 767 { 768 struct node_tinit *ti, *nti; 769 struct node_host *h; 770 771 printf("table <%s>", name); 772 if (flags & PFR_TFLAG_CONST) 773 printf(" const"); 774 if (flags & PFR_TFLAG_PERSIST) 775 printf(" persist"); 776 SIMPLEQ_FOREACH(ti, nodes, entries) { 777 if (ti->file) { 778 printf(" file \"%s\"", ti->file); 779 continue; 780 } 781 printf(" {"); 782 for (;;) { 783 for (h = ti->host; h != NULL; h = h->next) { 784 printf(h->not ? " !" : " "); 785 print_addr(&h->addr, h->af, 0); 786 } 787 nti = SIMPLEQ_NEXT(ti, entries); 788 if (nti != NULL && nti->file == NULL) 789 ti = nti; /* merge lists */ 790 else 791 break; 792 } 793 printf(" }"); 794 } 795 if (addrs && SIMPLEQ_EMPTY(nodes)) 796 printf(" { }"); 797 printf("\n"); 798 } 799 800 int 801 parse_flags(char *s) 802 { 803 char *p, *q; 804 u_int8_t f = 0; 805 806 for (p = s; *p; p++) { 807 if ((q = strchr(tcpflags, *p)) == NULL) 808 return -1; 809 else 810 f |= 1 << (q - tcpflags); 811 } 812 return (f ? f : PF_TH_ALL); 813 } 814 815 void 816 set_ipmask(struct node_host *h, u_int8_t b) 817 { 818 struct pf_addr *m, *n; 819 int i, j = 0; 820 821 m = &h->addr.v.a.mask; 822 823 for (i = 0; i < 4; i++) 824 m->addr32[i] = 0; 825 826 while (b >= 32) { 827 m->addr32[j++] = 0xffffffff; 828 b -= 32; 829 } 830 for (i = 31; i > 31-b; --i) 831 m->addr32[j] |= (1 << i); 832 if (b) 833 m->addr32[j] = htonl(m->addr32[j]); 834 835 /* Mask off bits of the address that will never be used. */ 836 n = &h->addr.v.a.addr; 837 if (h->addr.type == PF_ADDR_ADDRMASK) 838 for (i = 0; i < 4; i++) 839 n->addr32[i] = n->addr32[i] & m->addr32[i]; 840 } 841 842 int 843 check_netmask(struct node_host *h, sa_family_t af) 844 { 845 struct node_host *n = NULL; 846 struct pf_addr *m; 847 848 for (n = h; n != NULL; n = n->next) { 849 m = &h->addr.v.a.mask; 850 /* fix up netmask for dynaddr */ 851 if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL && 852 unmask(m, AF_INET6) > 32) 853 set_ipmask(n, 32); 854 /* netmasks > 32 bit are invalid on v4 */ 855 if (af == AF_INET && 856 (m->addr32[1] || m->addr32[2] || m->addr32[3])) { 857 fprintf(stderr, "netmask %u invalid for IPv4 address\n", 858 unmask(m, AF_INET6)); 859 return (1); 860 } 861 } 862 return (0); 863 } 864 865 /* interface lookup routines */ 866 867 struct node_host *iftab; 868 869 void 870 ifa_load(void) 871 { 872 struct ifaddrs *ifap, *ifa; 873 struct node_host *n = NULL, *h = NULL; 874 875 if (getifaddrs(&ifap) < 0) 876 err(1, "getifaddrs"); 877 878 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 879 if (!(ifa->ifa_addr->sa_family == AF_INET || 880 ifa->ifa_addr->sa_family == AF_INET6 || 881 ifa->ifa_addr->sa_family == AF_LINK)) 882 continue; 883 n = calloc(1, sizeof(struct node_host)); 884 if (n == NULL) 885 err(1, "address: calloc"); 886 n->af = ifa->ifa_addr->sa_family; 887 n->ifa_flags = ifa->ifa_flags; 888 #ifdef __KAME__ 889 if (n->af == AF_INET6 && 890 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) 891 ifa->ifa_addr)->sin6_addr) && 892 ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) { 893 struct sockaddr_in6 *sin6; 894 895 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 896 sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | 897 sin6->sin6_addr.s6_addr[3]; 898 sin6->sin6_addr.s6_addr[2] = 0; 899 sin6->sin6_addr.s6_addr[3] = 0; 900 } 901 #endif 902 n->ifindex = 0; 903 if (n->af == AF_INET) { 904 memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *) 905 ifa->ifa_addr)->sin_addr.s_addr, 906 sizeof(struct in_addr)); 907 memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *) 908 ifa->ifa_netmask)->sin_addr.s_addr, 909 sizeof(struct in_addr)); 910 if (ifa->ifa_broadaddr != NULL) 911 memcpy(&n->bcast, &((struct sockaddr_in *) 912 ifa->ifa_broadaddr)->sin_addr.s_addr, 913 sizeof(struct in_addr)); 914 } else if (n->af == AF_INET6) { 915 memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) 916 ifa->ifa_addr)->sin6_addr.s6_addr, 917 sizeof(struct in6_addr)); 918 memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *) 919 ifa->ifa_netmask)->sin6_addr.s6_addr, 920 sizeof(struct in6_addr)); 921 if (ifa->ifa_broadaddr != NULL) 922 memcpy(&n->bcast, &((struct sockaddr_in6 *) 923 ifa->ifa_broadaddr)->sin6_addr.s6_addr, 924 sizeof(struct in6_addr)); 925 n->ifindex = ((struct sockaddr_in6 *) 926 ifa->ifa_addr)->sin6_scope_id; 927 } 928 if ((n->ifname = strdup(ifa->ifa_name)) == NULL) 929 err(1, "ifa_load: strdup"); 930 n->next = NULL; 931 n->tail = n; 932 if (h == NULL) 933 h = n; 934 else { 935 h->tail->next = n; 936 h->tail = n; 937 } 938 } 939 iftab = h; 940 freeifaddrs(ifap); 941 } 942 943 struct node_host * 944 ifa_exists(const char *ifa_name) 945 { 946 struct node_host *n; 947 948 if (iftab == NULL) 949 ifa_load(); 950 951 for (n = iftab; n; n = n->next) { 952 if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) 953 return (n); 954 } 955 return (NULL); 956 } 957 958 struct node_host * 959 ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode) 960 { 961 struct node_host *p = NULL, *h = NULL, *n = NULL; 962 int return_all = 0; 963 964 if (!strncmp(ifa_name, "self", IFNAMSIZ)) 965 return_all = 1; 966 967 if (iftab == NULL) 968 ifa_load(); 969 970 for (p = iftab; p; p = p->next) { 971 if (!((p->af == AF_INET || p->af == AF_INET6) && 972 (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all))) 973 continue; 974 if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET) 975 continue; 976 if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0) 977 continue; 978 n = calloc(1, sizeof(struct node_host)); 979 if (n == NULL) 980 err(1, "address: calloc"); 981 n->af = p->af; 982 if (mode == PFCTL_IFLOOKUP_BCAST) 983 memcpy(&n->addr.v.a.addr, &p->bcast, 984 sizeof(struct pf_addr)); 985 else 986 memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, 987 sizeof(struct pf_addr)); 988 if (mode == PFCTL_IFLOOKUP_NET) 989 set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); 990 else { 991 if (n->af == AF_INET) { 992 if (p->ifa_flags & IFF_LOOPBACK && 993 p->ifa_flags & IFF_LINK1) 994 memcpy(&n->addr.v.a.mask, 995 &p->addr.v.a.mask, 996 sizeof(struct pf_addr)); 997 else 998 set_ipmask(n, 32); 999 } else 1000 set_ipmask(n, 128); 1001 } 1002 n->ifindex = p->ifindex; 1003 1004 n->next = NULL; 1005 n->tail = n; 1006 if (h == NULL) 1007 h = n; 1008 else { 1009 h->tail->next = n; 1010 h->tail = n; 1011 } 1012 } 1013 if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) { 1014 fprintf(stderr, "no IP address found for %s\n", ifa_name); 1015 } 1016 return (h); 1017 } 1018 1019 struct node_host * 1020 host(const char *s) 1021 { 1022 struct node_host *h = NULL; 1023 int mask, v4mask, v6mask, cont = 1; 1024 char *p, *q, *ps; 1025 1026 if ((p = strrchr(s, '/')) != NULL) { 1027 mask = strtol(p+1, &q, 0); 1028 if (!q || *q || mask > 128 || q == (p+1)) { 1029 fprintf(stderr, "invalid netmask\n"); 1030 return (NULL); 1031 } 1032 if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) 1033 err(1, "host: malloc"); 1034 strlcpy(ps, s, strlen(s) - strlen(p) + 1); 1035 v4mask = v6mask = mask; 1036 } else { 1037 if ((ps = strdup(s)) == NULL) 1038 err(1, "host: strdup"); 1039 v4mask = 32; 1040 v6mask = 128; 1041 mask = -1; 1042 } 1043 1044 /* interface with this name exists? */ 1045 if (cont && (h = host_if(ps, mask)) != NULL) 1046 cont = 0; 1047 1048 /* IPv4 address? */ 1049 if (cont && (h = host_v4(s, mask)) != NULL) 1050 cont = 0; 1051 1052 /* IPv6 address? */ 1053 if (cont && (h = host_v6(ps, v6mask)) != NULL) 1054 cont = 0; 1055 1056 /* dns lookup */ 1057 if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL) 1058 cont = 0; 1059 free(ps); 1060 1061 if (h == NULL || cont == 1) { 1062 fprintf(stderr, "no IP address found for %s\n", s); 1063 return (NULL); 1064 } 1065 return (h); 1066 } 1067 1068 struct node_host * 1069 host_if(const char *s, int mask) 1070 { 1071 struct node_host *n, *h = NULL; 1072 char *p, *ps; 1073 int mode = PFCTL_IFLOOKUP_HOST; 1074 1075 if ((p = strrchr(s, ':')) != NULL && 1076 (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) { 1077 if (!strcmp(p+1, "network")) 1078 mode = PFCTL_IFLOOKUP_NET; 1079 if (!strcmp(p+1, "broadcast")) 1080 mode = PFCTL_IFLOOKUP_BCAST; 1081 if (mask > -1) { 1082 fprintf(stderr, "network or broadcast lookup, but " 1083 "extra netmask given\n"); 1084 return (NULL); 1085 } 1086 if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) 1087 err(1, "host: malloc"); 1088 strlcpy(ps, s, strlen(s) - strlen(p) + 1); 1089 } else 1090 if ((ps = strdup(s)) == NULL) 1091 err(1, "host_if: strdup"); 1092 1093 if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { 1094 /* interface with this name exists */ 1095 h = ifa_lookup(ps, mode); 1096 for (n = h; n != NULL && mask > -1; n = n->next) 1097 set_ipmask(n, mask); 1098 } 1099 1100 free(ps); 1101 return (h); 1102 } 1103 1104 struct node_host * 1105 host_v4(const char *s, int mask) 1106 { 1107 struct node_host *h = NULL; 1108 struct in_addr ina; 1109 int bits; 1110 1111 memset(&ina, 0, sizeof(struct in_addr)); 1112 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) > -1) { 1113 h = calloc(1, sizeof(struct node_host)); 1114 if (h == NULL) 1115 err(1, "address: calloc"); 1116 h->ifname = NULL; 1117 h->af = AF_INET; 1118 h->addr.v.a.addr.addr32[0] = ina.s_addr; 1119 set_ipmask(h, bits); 1120 h->next = NULL; 1121 h->tail = h; 1122 } 1123 1124 return (h); 1125 } 1126 1127 struct node_host * 1128 host_v6(const char *s, int mask) 1129 { 1130 struct addrinfo hints, *res; 1131 struct node_host *h = NULL; 1132 1133 memset(&hints, 0, sizeof(hints)); 1134 hints.ai_family = AF_INET6; 1135 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 1136 hints.ai_flags = AI_NUMERICHOST; 1137 if (getaddrinfo(s, "0", &hints, &res) == 0) { 1138 h = calloc(1, sizeof(struct node_host)); 1139 if (h == NULL) 1140 err(1, "address: calloc"); 1141 h->ifname = NULL; 1142 h->af = AF_INET6; 1143 memcpy(&h->addr.v.a.addr, 1144 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 1145 sizeof(h->addr.v.a.addr)); 1146 h->ifindex = 1147 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 1148 set_ipmask(h, mask); 1149 freeaddrinfo(res); 1150 h->next = NULL; 1151 h->tail = h; 1152 } 1153 1154 return (h); 1155 } 1156 1157 struct node_host * 1158 host_dns(const char *s, int v4mask, int v6mask) 1159 { 1160 struct addrinfo hints, *res0, *res; 1161 struct node_host *n, *h = NULL; 1162 int error; 1163 1164 memset(&hints, 0, sizeof(hints)); 1165 hints.ai_family = PF_UNSPEC; 1166 hints.ai_socktype = SOCK_STREAM; /* DUMMY */ 1167 error = getaddrinfo(s, NULL, &hints, &res0); 1168 if (error) 1169 return (h); 1170 1171 for (res = res0; res; res = res->ai_next) { 1172 if (res->ai_family != AF_INET && 1173 res->ai_family != AF_INET6) 1174 continue; 1175 n = calloc(1, sizeof(struct node_host)); 1176 if (n == NULL) 1177 err(1, "host_dns: calloc"); 1178 n->ifname = NULL; 1179 n->af = res->ai_family; 1180 if (res->ai_family == AF_INET) { 1181 memcpy(&n->addr.v.a.addr, 1182 &((struct sockaddr_in *) 1183 res->ai_addr)->sin_addr.s_addr, 1184 sizeof(struct in_addr)); 1185 set_ipmask(n, v4mask); 1186 } else { 1187 memcpy(&n->addr.v.a.addr, 1188 &((struct sockaddr_in6 *) 1189 res->ai_addr)->sin6_addr.s6_addr, 1190 sizeof(struct in6_addr)); 1191 n->ifindex = 1192 ((struct sockaddr_in6 *) 1193 res->ai_addr)->sin6_scope_id; 1194 set_ipmask(n, v6mask); 1195 } 1196 n->next = NULL; 1197 n->tail = n; 1198 if (h == NULL) 1199 h = n; 1200 else { 1201 h->tail->next = n; 1202 h->tail = n; 1203 } 1204 } 1205 freeaddrinfo(res0); 1206 1207 return (h); 1208 } 1209 1210 /* 1211 * convert a hostname to a list of addresses and put them in the given buffer. 1212 * test: 1213 * if set to 1, only simple addresses are accepted (no netblock, no "!"). 1214 */ 1215 int 1216 append_addr(struct pfr_buffer *b, char *s, int test) 1217 { 1218 char *r; 1219 struct node_host *h, *n; 1220 int rv, not = 0; 1221 1222 for (r = s; *r == '!'; r++) 1223 not = !not; 1224 if ((n = host(r)) == NULL) { 1225 errno = 0; 1226 return (-1); 1227 } 1228 rv = append_addr_host(b, n, test, not); 1229 do { 1230 h = n; 1231 n = n->next; 1232 free(h); 1233 } while (n != NULL); 1234 return (rv); 1235 } 1236 1237 /* 1238 * same as previous function, but with a pre-parsed input and the ability 1239 * to "negate" the result. Does not free the node_host list. 1240 * not: 1241 * setting it to 1 is equivalent to adding "!" in front of parameter s. 1242 */ 1243 int 1244 append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not) 1245 { 1246 int bits; 1247 struct pfr_addr addr; 1248 1249 do { 1250 bzero(&addr, sizeof(addr)); 1251 addr.pfra_not = n->not ^ not; 1252 addr.pfra_af = n->af; 1253 addr.pfra_net = unmask(&n->addr.v.a.mask, n->af); 1254 switch (n->af) { 1255 case AF_INET: 1256 addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0]; 1257 bits = 32; 1258 break; 1259 case AF_INET6: 1260 memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6, 1261 sizeof(struct in6_addr)); 1262 bits = 128; 1263 break; 1264 default: 1265 errno = EINVAL; 1266 return (-1); 1267 } 1268 if ((test && (not || addr.pfra_net != bits)) || 1269 addr.pfra_net > bits) { 1270 errno = EINVAL; 1271 return (-1); 1272 } 1273 if (pfr_buf_add(b, &addr)) 1274 return (-1); 1275 } while ((n = n->next) != NULL); 1276 1277 return (0); 1278 } 1279