1 /* $OpenBSD: pfctl_parser.c,v 1.292 2013/01/16 01:49:20 henning Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Daniel Hartmeier 5 * Copyright (c) 2002,2003 Henning Brauer 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/ioctl.h> 36 #include <sys/socket.h> 37 #include <net/if.h> 38 #include <netinet/in.h> 39 #include <netinet/in_systm.h> 40 #include <netinet/ip.h> 41 #include <netinet/ip_icmp.h> 42 #include <netinet/icmp6.h> 43 #include <net/pfvar.h> 44 #include <arpa/inet.h> 45 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <ctype.h> 50 #include <netdb.h> 51 #include <stdarg.h> 52 #include <errno.h> 53 #include <err.h> 54 #include <ifaddrs.h> 55 #include <unistd.h> 56 57 #define SYSLOG_NAMES 58 #include <syslog.h> 59 60 #include "pfctl_parser.h" 61 #include "pfctl.h" 62 63 void print_op (u_int8_t, const char *, const char *); 64 void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int); 65 void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); 66 void print_flags (u_int8_t); 67 void print_fromto(struct pf_rule_addr *, pf_osfp_t, 68 struct pf_rule_addr *, u_int8_t, u_int8_t, int); 69 int ifa_skip_if(const char *filter, struct node_host *p); 70 71 struct node_host *ifa_grouplookup(const char *, int); 72 struct node_host *host_if(const char *, int); 73 struct node_host *host_v4(const char *, int); 74 struct node_host *host_v6(const char *, int); 75 struct node_host *host_dns(const char *, int, int); 76 77 const char *tcpflags = "FSRPAUEW"; 78 79 static 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 107 static 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 136 static 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 169 static 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 184 const 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 { "tcp.tsdiff", PFTM_TS_DIFF }, 192 { "udp.first", PFTM_UDP_FIRST_PACKET }, 193 { "udp.single", PFTM_UDP_SINGLE }, 194 { "udp.multiple", PFTM_UDP_MULTIPLE }, 195 { "icmp.first", PFTM_ICMP_FIRST_PACKET }, 196 { "icmp.error", PFTM_ICMP_ERROR_REPLY }, 197 { "other.first", PFTM_OTHER_FIRST_PACKET }, 198 { "other.single", PFTM_OTHER_SINGLE }, 199 { "other.multiple", PFTM_OTHER_MULTIPLE }, 200 { "frag", PFTM_FRAG }, 201 { "interval", PFTM_INTERVAL }, 202 { "adaptive.start", PFTM_ADAPTIVE_START }, 203 { "adaptive.end", PFTM_ADAPTIVE_END }, 204 { "src.track", PFTM_SRC_NODE }, 205 { NULL, 0 } 206 }; 207 208 enum { PF_POOL_ROUTE, PF_POOL_NAT, PF_POOL_RDR }; 209 210 const struct icmptypeent * 211 geticmptypebynumber(u_int8_t type, sa_family_t af) 212 { 213 unsigned int i; 214 215 if (af != AF_INET6) { 216 for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); 217 i++) { 218 if (type == icmp_type[i].type) 219 return (&icmp_type[i]); 220 } 221 } else { 222 for (i=0; i < (sizeof (icmp6_type) / 223 sizeof(icmp6_type[0])); i++) { 224 if (type == icmp6_type[i].type) 225 return (&icmp6_type[i]); 226 } 227 } 228 return (NULL); 229 } 230 231 const struct icmptypeent * 232 geticmptypebyname(char *w, sa_family_t af) 233 { 234 unsigned int i; 235 236 if (af != AF_INET6) { 237 for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); 238 i++) { 239 if (!strcmp(w, icmp_type[i].name)) 240 return (&icmp_type[i]); 241 } 242 } else { 243 for (i=0; i < (sizeof (icmp6_type) / 244 sizeof(icmp6_type[0])); i++) { 245 if (!strcmp(w, icmp6_type[i].name)) 246 return (&icmp6_type[i]); 247 } 248 } 249 return (NULL); 250 } 251 252 const struct icmpcodeent * 253 geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) 254 { 255 unsigned int i; 256 257 if (af != AF_INET6) { 258 for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); 259 i++) { 260 if (type == icmp_code[i].type && 261 code == icmp_code[i].code) 262 return (&icmp_code[i]); 263 } 264 } else { 265 for (i=0; i < (sizeof (icmp6_code) / 266 sizeof(icmp6_code[0])); i++) { 267 if (type == icmp6_code[i].type && 268 code == icmp6_code[i].code) 269 return (&icmp6_code[i]); 270 } 271 } 272 return (NULL); 273 } 274 275 const struct icmpcodeent * 276 geticmpcodebyname(u_long type, char *w, sa_family_t af) 277 { 278 unsigned int i; 279 280 if (af != AF_INET6) { 281 for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); 282 i++) { 283 if (type == icmp_code[i].type && 284 !strcmp(w, icmp_code[i].name)) 285 return (&icmp_code[i]); 286 } 287 } else { 288 for (i=0; i < (sizeof (icmp6_code) / 289 sizeof(icmp6_code[0])); i++) { 290 if (type == icmp6_code[i].type && 291 !strcmp(w, icmp6_code[i].name)) 292 return (&icmp6_code[i]); 293 } 294 } 295 return (NULL); 296 } 297 298 /* 299 * Decode a symbolic name to a numeric value. 300 * From syslogd. 301 */ 302 int 303 string_to_loglevel(const char *name) 304 { 305 CODE *c; 306 char *p, buf[40]; 307 308 if (isdigit(*name)) 309 return (atoi(name)); 310 311 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 312 if (isupper(*name)) 313 *p = tolower(*name); 314 else 315 *p = *name; 316 } 317 *p = '\0'; 318 for (c = prioritynames; c->c_name; c++) 319 if (!strcmp(buf, c->c_name) && c->c_val != INTERNAL_NOPRI) 320 return (c->c_val); 321 322 return (-1); 323 } 324 325 const char * 326 loglevel_to_string(int level) 327 { 328 CODE *c; 329 330 for (c = prioritynames; c->c_name; c++) 331 if (c->c_val == level) 332 return (c->c_name); 333 334 return ("unknown"); 335 } 336 337 void 338 print_op(u_int8_t op, const char *a1, const char *a2) 339 { 340 if (op == PF_OP_IRG) 341 printf(" %s >< %s", a1, a2); 342 else if (op == PF_OP_XRG) 343 printf(" %s <> %s", a1, a2); 344 else if (op == PF_OP_EQ) 345 printf(" = %s", a1); 346 else if (op == PF_OP_NE) 347 printf(" != %s", a1); 348 else if (op == PF_OP_LT) 349 printf(" < %s", a1); 350 else if (op == PF_OP_LE) 351 printf(" <= %s", a1); 352 else if (op == PF_OP_GT) 353 printf(" > %s", a1); 354 else if (op == PF_OP_GE) 355 printf(" >= %s", a1); 356 else if (op == PF_OP_RRG) 357 printf(" %s:%s", a1, a2); 358 } 359 360 void 361 print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int opts) 362 { 363 char a1[6], a2[6]; 364 struct servent *s = NULL; 365 366 if (opts & PF_OPT_PORTNAMES) 367 s = getservbyport(p1, proto); 368 p1 = ntohs(p1); 369 p2 = ntohs(p2); 370 snprintf(a1, sizeof(a1), "%u", p1); 371 snprintf(a2, sizeof(a2), "%u", p2); 372 printf(" port"); 373 if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) 374 print_op(op, s->s_name, a2); 375 else 376 print_op(op, a1, a2); 377 } 378 379 void 380 print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax) 381 { 382 char a1[11], a2[11]; 383 384 snprintf(a1, sizeof(a1), "%u", u1); 385 snprintf(a2, sizeof(a2), "%u", u2); 386 printf(" %s", t); 387 if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) 388 print_op(op, "unknown", a2); 389 else 390 print_op(op, a1, a2); 391 } 392 393 void 394 print_flags(u_int8_t f) 395 { 396 int i; 397 398 for (i = 0; tcpflags[i]; ++i) 399 if (f & (1 << i)) 400 printf("%c", tcpflags[i]); 401 } 402 403 void 404 print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst, 405 sa_family_t af, u_int8_t proto, int opts) 406 { 407 char buf[PF_OSFP_LEN*3]; 408 int verbose = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); 409 if (src->addr.type == PF_ADDR_ADDRMASK && 410 dst->addr.type == PF_ADDR_ADDRMASK && 411 PF_AZERO(&src->addr.v.a.addr, AF_INET6) && 412 PF_AZERO(&src->addr.v.a.mask, AF_INET6) && 413 PF_AZERO(&dst->addr.v.a.addr, AF_INET6) && 414 PF_AZERO(&dst->addr.v.a.mask, AF_INET6) && 415 !src->neg && !dst->neg && 416 !src->port_op && !dst->port_op && 417 osfp == PF_OSFP_ANY) 418 printf(" all"); 419 else { 420 printf(" from "); 421 if (src->neg) 422 printf("! "); 423 print_addr(&src->addr, af, verbose); 424 if (src->port_op) 425 print_port(src->port_op, src->port[0], 426 src->port[1], 427 proto == IPPROTO_TCP ? "tcp" : "udp", opts); 428 if (osfp != PF_OSFP_ANY) 429 printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf, 430 sizeof(buf))); 431 432 printf(" to "); 433 if (dst->neg) 434 printf("! "); 435 print_addr(&dst->addr, af, verbose); 436 if (dst->port_op) 437 print_port(dst->port_op, dst->port[0], 438 dst->port[1], 439 proto == IPPROTO_TCP ? "tcp" : "udp", opts); 440 } 441 } 442 443 void 444 print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, 445 sa_family_t af, int id, int verbose) 446 { 447 if (pool->ifname[0]) { 448 if (!PF_AZERO(&pool->addr.v.a.addr, af)) { 449 print_addr(&pool->addr, af, verbose); 450 printf("@"); 451 } 452 printf("%s", pool->ifname); 453 } else 454 print_addr(&pool->addr, af, verbose); 455 switch (id) { 456 case PF_POOL_NAT: 457 if ((p1 != PF_NAT_PROXY_PORT_LOW || 458 p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) { 459 if (p1 == p2) 460 printf(" port %u", p1); 461 else 462 printf(" port %u:%u", p1, p2); 463 } 464 break; 465 case PF_POOL_RDR: 466 if (p1) { 467 printf(" port %u", p1); 468 if (p2 && (p2 != p1)) 469 printf(":%u", p2); 470 } 471 break; 472 default: 473 break; 474 } 475 switch (pool->opts & PF_POOL_TYPEMASK) { 476 case PF_POOL_NONE: 477 break; 478 case PF_POOL_BITMASK: 479 printf(" bitmask"); 480 break; 481 case PF_POOL_RANDOM: 482 printf(" random"); 483 break; 484 case PF_POOL_SRCHASH: 485 printf(" source-hash 0x%08x%08x%08x%08x", 486 pool->key.key32[0], pool->key.key32[1], 487 pool->key.key32[2], pool->key.key32[3]); 488 break; 489 case PF_POOL_ROUNDROBIN: 490 printf(" round-robin"); 491 break; 492 case PF_POOL_LEASTSTATES: 493 printf(" least-states"); 494 break; 495 } 496 if (pool->opts & PF_POOL_STICKYADDR) 497 printf(" sticky-address"); 498 if (id == PF_POOL_NAT && p1 == 0 && p2 == 0) 499 printf(" static-port"); 500 } 501 502 const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; 503 const char *pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; 504 const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; 505 const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; 506 507 void 508 print_status(struct pf_status *s, int opts) 509 { 510 char statline[80], *running, *debug; 511 time_t runtime; 512 int i; 513 char buf[PF_MD5_DIGEST_LENGTH * 2 + 1]; 514 static const char hex[] = "0123456789abcdef"; 515 516 runtime = time(NULL) - s->since; 517 running = s->running ? "Enabled" : "Disabled"; 518 519 if (s->since) { 520 unsigned int sec, min, hrs, day = runtime; 521 522 sec = day % 60; 523 day /= 60; 524 min = day % 60; 525 day /= 60; 526 hrs = day % 24; 527 day /= 24; 528 snprintf(statline, sizeof(statline), 529 "Status: %s for %u days %.2u:%.2u:%.2u", 530 running, day, hrs, min, sec); 531 } else 532 snprintf(statline, sizeof(statline), "Status: %s", running); 533 printf("%-44s", statline); 534 asprintf(&debug, "Debug: %s", loglevel_to_string(s->debug)); 535 printf("%15s\n\n", debug); 536 free(debug); 537 538 if (opts & PF_OPT_VERBOSE) { 539 printf("Hostid: 0x%08x\n", ntohl(s->hostid)); 540 541 for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) { 542 buf[i + i] = hex[s->pf_chksum[i] >> 4]; 543 buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f]; 544 } 545 buf[i + i] = '\0'; 546 printf("Checksum: 0x%s\n\n", buf); 547 } 548 549 if (s->ifname[0] != 0) { 550 printf("Interface Stats for %-16s %5s %16s\n", 551 s->ifname, "IPv4", "IPv6"); 552 printf(" %-25s %14llu %16llu\n", "Bytes In", 553 (unsigned long long)s->bcounters[0][0], 554 (unsigned long long)s->bcounters[1][0]); 555 printf(" %-25s %14llu %16llu\n", "Bytes Out", 556 (unsigned long long)s->bcounters[0][1], 557 (unsigned long long)s->bcounters[1][1]); 558 printf(" Packets In\n"); 559 printf(" %-23s %14llu %16llu\n", "Passed", 560 (unsigned long long)s->pcounters[0][0][PF_PASS], 561 (unsigned long long)s->pcounters[1][0][PF_PASS]); 562 printf(" %-23s %14llu %16llu\n", "Blocked", 563 (unsigned long long)s->pcounters[0][0][PF_DROP], 564 (unsigned long long)s->pcounters[1][0][PF_DROP]); 565 printf(" Packets Out\n"); 566 printf(" %-23s %14llu %16llu\n", "Passed", 567 (unsigned long long)s->pcounters[0][1][PF_PASS], 568 (unsigned long long)s->pcounters[1][1][PF_PASS]); 569 printf(" %-23s %14llu %16llu\n\n", "Blocked", 570 (unsigned long long)s->pcounters[0][1][PF_DROP], 571 (unsigned long long)s->pcounters[1][1][PF_DROP]); 572 } 573 printf("%-27s %14s %16s\n", "State Table", "Total", "Rate"); 574 printf(" %-25s %14u %14s\n", "current entries", s->states, ""); 575 for (i = 0; i < FCNT_MAX; i++) { 576 printf(" %-25s %14llu ", pf_fcounters[i], 577 (unsigned long long)s->fcounters[i]); 578 if (runtime > 0) 579 printf("%14.1f/s\n", 580 (double)s->fcounters[i] / (double)runtime); 581 else 582 printf("%14s\n", ""); 583 } 584 if (opts & PF_OPT_VERBOSE) { 585 printf("Source Tracking Table\n"); 586 printf(" %-25s %14u %14s\n", "current entries", 587 s->src_nodes, ""); 588 for (i = 0; i < SCNT_MAX; i++) { 589 printf(" %-25s %14lld ", pf_scounters[i], 590 s->scounters[i]); 591 if (runtime > 0) 592 printf("%14.1f/s\n", 593 (double)s->scounters[i] / (double)runtime); 594 else 595 printf("%14s\n", ""); 596 } 597 } 598 printf("Counters\n"); 599 for (i = 0; i < PFRES_MAX; i++) { 600 printf(" %-25s %14llu ", pf_reasons[i], 601 (unsigned long long)s->counters[i]); 602 if (runtime > 0) 603 printf("%14.1f/s\n", 604 (double)s->counters[i] / (double)runtime); 605 else 606 printf("%14s\n", ""); 607 } 608 if (opts & PF_OPT_VERBOSE) { 609 printf("Limit Counters\n"); 610 for (i = 0; i < LCNT_MAX; i++) { 611 printf(" %-25s %14lld ", pf_lcounters[i], 612 s->lcounters[i]); 613 if (runtime > 0) 614 printf("%14.1f/s\n", 615 (double)s->lcounters[i] / (double)runtime); 616 else 617 printf("%14s\n", ""); 618 } 619 } 620 } 621 622 void 623 print_src_node(struct pf_src_node *sn, int opts) 624 { 625 struct pf_addr_wrap aw; 626 int min, sec; 627 628 memset(&aw, 0, sizeof(aw)); 629 if (sn->af == AF_INET) 630 aw.v.a.mask.addr32[0] = 0xffffffff; 631 else 632 memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); 633 634 aw.v.a.addr = sn->addr; 635 print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); 636 637 if (!PF_AZERO(&sn->raddr, sn->af)) { 638 if (sn->type == PF_SN_NAT) 639 printf(" nat-to "); 640 else if (sn->type == PF_SN_RDR) 641 printf(" rdr-to "); 642 else if (sn->type == PF_SN_ROUTE) 643 printf(" route-to "); 644 else 645 printf(" ??? (%u) ", sn->type); 646 aw.v.a.addr = sn->raddr; 647 print_addr(&aw, sn->naf ? sn->naf : sn->af, 648 opts & PF_OPT_VERBOSE2); 649 } 650 651 printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states, 652 sn->conn, sn->conn_rate.count / 1000, 653 (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds); 654 if (opts & PF_OPT_VERBOSE) { 655 sec = sn->creation % 60; 656 sn->creation /= 60; 657 min = sn->creation % 60; 658 sn->creation /= 60; 659 printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec); 660 if (sn->states == 0) { 661 sec = sn->expire % 60; 662 sn->expire /= 60; 663 min = sn->expire % 60; 664 sn->expire /= 60; 665 printf(", expires in %.2u:%.2u:%.2u", 666 sn->expire, min, sec); 667 } 668 printf(", %llu pkts, %llu bytes", 669 sn->packets[0] + sn->packets[1], 670 sn->bytes[0] + sn->bytes[1]); 671 if (sn->rule.nr != -1) 672 printf(", rule %u", sn->rule.nr); 673 printf("\n"); 674 } 675 } 676 677 void 678 print_rule(struct pf_rule *r, const char *anchor_call, int opts) 679 { 680 static const char *actiontypes[] = { "pass", "block", "scrub", 681 "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr", 682 "", "", "match"}; 683 static const char *anchortypes[] = { "anchor", "anchor", "anchor", 684 "anchor", "nat-anchor", "nat-anchor", "binat-anchor", 685 "binat-anchor", "rdr-anchor", "rdr-anchor" }; 686 int i, ropts; 687 int verbose = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); 688 char *p; 689 690 if (verbose) 691 printf("@%d ", r->nr); 692 if (r->action > PF_MATCH) 693 printf("action(%d)", r->action); 694 else if (anchor_call[0]) { 695 p = strrchr(anchor_call, '/'); 696 if (p ? p[1] == '_' : anchor_call[0] == '_') 697 printf("%s", anchortypes[r->action]); 698 else 699 printf("%s \"%s\"", anchortypes[r->action], 700 anchor_call); 701 } else 702 printf("%s", actiontypes[r->action]); 703 if (r->action == PF_DROP) { 704 if (r->rule_flag & PFRULE_RETURN) 705 printf(" return"); 706 else if (r->rule_flag & PFRULE_RETURNRST) { 707 if (!r->return_ttl) 708 printf(" return-rst"); 709 else 710 printf(" return-rst(ttl %d)", r->return_ttl); 711 } else if (r->rule_flag & PFRULE_RETURNICMP) { 712 const struct icmpcodeent *ic, *ic6; 713 714 ic = geticmpcodebynumber(r->return_icmp >> 8, 715 r->return_icmp & 255, AF_INET); 716 ic6 = geticmpcodebynumber(r->return_icmp6 >> 8, 717 r->return_icmp6 & 255, AF_INET6); 718 719 switch (r->af) { 720 case AF_INET: 721 printf(" return-icmp"); 722 if (ic == NULL) 723 printf("(%u)", r->return_icmp & 255); 724 else 725 printf("(%s)", ic->name); 726 break; 727 case AF_INET6: 728 printf(" return-icmp6"); 729 if (ic6 == NULL) 730 printf("(%u)", r->return_icmp6 & 255); 731 else 732 printf("(%s)", ic6->name); 733 break; 734 default: 735 printf(" return-icmp"); 736 if (ic == NULL) 737 printf("(%u, ", r->return_icmp & 255); 738 else 739 printf("(%s, ", ic->name); 740 if (ic6 == NULL) 741 printf("%u)", r->return_icmp6 & 255); 742 else 743 printf("%s)", ic6->name); 744 break; 745 } 746 } else 747 printf(" drop"); 748 } 749 if (r->direction == PF_IN) 750 printf(" in"); 751 else if (r->direction == PF_OUT) 752 printf(" out"); 753 if (r->log) { 754 printf(" log"); 755 if (r->log & ~PF_LOG || r->logif) { 756 int count = 0; 757 758 printf(" ("); 759 if (r->log & PF_LOG_ALL) 760 printf("%sall", count++ ? ", " : ""); 761 if (r->log & PF_LOG_MATCHES) 762 printf("%smatches", count++ ? ", " : ""); 763 if (r->log & PF_LOG_SOCKET_LOOKUP) 764 printf("%suser", count++ ? ", " : ""); 765 if (r->logif) 766 printf("%sto pflog%u", count++ ? ", " : "", 767 r->logif); 768 printf(")"); 769 } 770 } 771 if (r->quick) 772 printf(" quick"); 773 if (r->ifname[0]) { 774 if (r->ifnot) 775 printf(" on ! %s", r->ifname); 776 else 777 printf(" on %s", r->ifname); 778 } 779 if (r->onrdomain >= 0) { 780 if (r->ifnot) 781 printf(" on ! rdomain %i", r->onrdomain); 782 else 783 printf(" on rdomain %i", r->onrdomain); 784 } 785 if (r->af) { 786 if (r->af == AF_INET) 787 printf(" inet"); 788 else 789 printf(" inet6"); 790 } 791 if (r->proto) { 792 struct protoent *p; 793 794 if ((p = getprotobynumber(r->proto)) != NULL) 795 printf(" proto %s", p->p_name); 796 else 797 printf(" proto %u", r->proto); 798 } 799 print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto, 800 opts); 801 if (r->rcv_ifname[0]) 802 printf(" received-on %s", r->rcv_ifname); 803 if (r->uid.op) 804 print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", 805 UID_MAX); 806 if (r->gid.op) 807 print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", 808 GID_MAX); 809 if (r->flags || r->flagset) { 810 printf(" flags "); 811 print_flags(r->flags); 812 printf("/"); 813 print_flags(r->flagset); 814 } else if ((r->action == PF_PASS || r->action == PF_MATCH) && 815 (!r->proto || r->proto == IPPROTO_TCP) && 816 !(r->rule_flag & PFRULE_FRAGMENT) && 817 !anchor_call[0] && r->keep_state) 818 printf(" flags any"); 819 if (r->type) { 820 const struct icmptypeent *it; 821 822 it = geticmptypebynumber(r->type-1, r->af); 823 if (r->af != AF_INET6) 824 printf(" icmp-type"); 825 else 826 printf(" icmp6-type"); 827 if (it != NULL) 828 printf(" %s", it->name); 829 else 830 printf(" %u", r->type-1); 831 if (r->code) { 832 const struct icmpcodeent *ic; 833 834 ic = geticmpcodebynumber(r->type-1, r->code-1, r->af); 835 if (ic != NULL) 836 printf(" code %s", ic->name); 837 else 838 printf(" code %u", r->code-1); 839 } 840 } 841 if (r->tos) 842 printf(" tos 0x%2.2x", r->tos); 843 844 if (r->scrub_flags & PFSTATE_SETMASK || r->qname[0]) { 845 char *comma = ""; 846 printf(" set ("); 847 if (r->scrub_flags & PFSTATE_SETPRIO) { 848 if (r->set_prio[0] == r->set_prio[1]) 849 printf("%s prio %u", comma, r->set_prio[0]); 850 else 851 printf("%s prio(%u, %u)", comma, r->set_prio[0], 852 r->set_prio[1]); 853 comma = ","; 854 } 855 if (r->qname[0]) { 856 if (r->pqname[0]) 857 printf("%s queue(%s, %s)", comma, r->qname, 858 r->pqname); 859 else 860 printf("%s queue %s", comma, r->qname); 861 comma = ","; 862 } 863 if (r->scrub_flags & PFSTATE_SETTOS) { 864 printf("%s tos 0x%2.2x", comma, r->set_tos); 865 comma = ","; 866 } 867 printf(" )"); 868 } 869 870 ropts = 0; 871 if (r->max_states || r->max_src_nodes || r->max_src_states) 872 ropts = 1; 873 if (r->rule_flag & PFRULE_NOSYNC) 874 ropts = 1; 875 if (r->rule_flag & PFRULE_SRCTRACK) 876 ropts = 1; 877 if (r->rule_flag & PFRULE_IFBOUND) 878 ropts = 1; 879 if (r->rule_flag & PFRULE_STATESLOPPY) 880 ropts = 1; 881 if (r->rule_flag & PFRULE_PFLOW) 882 ropts = 1; 883 for (i = 0; !ropts && i < PFTM_MAX; ++i) 884 if (r->timeout[i]) 885 ropts = 1; 886 887 if (!r->keep_state && r->action == PF_PASS && !anchor_call[0]) 888 printf(" no state"); 889 else if (r->keep_state == PF_STATE_NORMAL && ropts) 890 printf(" keep state"); 891 else if (r->keep_state == PF_STATE_MODULATE) 892 printf(" modulate state"); 893 else if (r->keep_state == PF_STATE_SYNPROXY) 894 printf(" synproxy state"); 895 if (r->prob) { 896 char buf[20]; 897 898 snprintf(buf, sizeof(buf), "%f", r->prob*100.0/(UINT_MAX+1.0)); 899 for (i = strlen(buf)-1; i > 0; i--) { 900 if (buf[i] == '0') 901 buf[i] = '\0'; 902 else { 903 if (buf[i] == '.') 904 buf[i] = '\0'; 905 break; 906 } 907 } 908 printf(" probability %s%%", buf); 909 } 910 if (ropts) { 911 printf(" ("); 912 if (r->max_states) { 913 printf("max %u", r->max_states); 914 ropts = 0; 915 } 916 if (r->rule_flag & PFRULE_NOSYNC) { 917 if (!ropts) 918 printf(", "); 919 printf("no-sync"); 920 ropts = 0; 921 } 922 if (r->rule_flag & PFRULE_SRCTRACK) { 923 if (!ropts) 924 printf(", "); 925 printf("source-track"); 926 if (r->rule_flag & PFRULE_RULESRCTRACK) 927 printf(" rule"); 928 else 929 printf(" global"); 930 ropts = 0; 931 } 932 if (r->max_src_states) { 933 if (!ropts) 934 printf(", "); 935 printf("max-src-states %u", r->max_src_states); 936 ropts = 0; 937 } 938 if (r->max_src_conn) { 939 if (!ropts) 940 printf(", "); 941 printf("max-src-conn %u", r->max_src_conn); 942 ropts = 0; 943 } 944 if (r->max_src_conn_rate.limit) { 945 if (!ropts) 946 printf(", "); 947 printf("max-src-conn-rate %u/%u", 948 r->max_src_conn_rate.limit, 949 r->max_src_conn_rate.seconds); 950 ropts = 0; 951 } 952 if (r->max_src_nodes) { 953 if (!ropts) 954 printf(", "); 955 printf("max-src-nodes %u", r->max_src_nodes); 956 ropts = 0; 957 } 958 if (r->overload_tblname[0]) { 959 if (!ropts) 960 printf(", "); 961 printf("overload <%s>", r->overload_tblname); 962 if (r->flush) 963 printf(" flush"); 964 if (r->flush & PF_FLUSH_GLOBAL) 965 printf(" global"); 966 } 967 if (r->rule_flag & PFRULE_IFBOUND) { 968 if (!ropts) 969 printf(", "); 970 printf("if-bound"); 971 ropts = 0; 972 } 973 if (r->rule_flag & PFRULE_STATESLOPPY) { 974 if (!ropts) 975 printf(", "); 976 printf("sloppy"); 977 ropts = 0; 978 } 979 if (r->rule_flag & PFRULE_PFLOW) { 980 if (!ropts) 981 printf(", "); 982 printf("pflow"); 983 ropts = 0; 984 } 985 for (i = 0; i < PFTM_MAX; ++i) 986 if (r->timeout[i]) { 987 int j; 988 989 if (!ropts) 990 printf(", "); 991 ropts = 0; 992 for (j = 0; pf_timeouts[j].name != NULL; 993 ++j) 994 if (pf_timeouts[j].timeout == i) 995 break; 996 printf("%s %u", pf_timeouts[j].name == NULL ? 997 "inv.timeout" : pf_timeouts[j].name, 998 r->timeout[i]); 999 } 1000 printf(")"); 1001 } 1002 1003 if (r->rule_flag & PFRULE_FRAGMENT) 1004 printf(" fragment"); 1005 1006 if (r->scrub_flags & PFSTATE_SCRUBMASK || r->min_ttl || r->max_mss) { 1007 printf(" scrub ("); 1008 ropts = 1; 1009 if (r->scrub_flags & PFSTATE_NODF) { 1010 printf("no-df"); 1011 ropts = 0; 1012 } 1013 if (r->scrub_flags & PFSTATE_RANDOMID) { 1014 if (!ropts) 1015 printf(" "); 1016 printf("random-id"); 1017 ropts = 0; 1018 } 1019 if (r->min_ttl) { 1020 if (!ropts) 1021 printf(" "); 1022 printf("min-ttl %d", r->min_ttl); 1023 ropts = 0; 1024 } 1025 if (r->scrub_flags & PFSTATE_SCRUB_TCP) { 1026 if (!ropts) 1027 printf(" "); 1028 printf("reassemble tcp"); 1029 ropts = 0; 1030 } 1031 if (r->max_mss) { 1032 if (!ropts) 1033 printf(" "); 1034 printf("max-mss %d", r->max_mss); 1035 ropts = 0; 1036 } 1037 printf(")"); 1038 } 1039 1040 if (r->allow_opts) 1041 printf(" allow-opts"); 1042 if (r->label[0]) 1043 printf(" label \"%s\"", r->label); 1044 if (r->rule_flag & PFRULE_ONCE) 1045 printf(" once"); 1046 if (r->tagname[0]) 1047 printf(" tag %s", r->tagname); 1048 if (r->match_tagname[0]) { 1049 if (r->match_tag_not) 1050 printf(" !"); 1051 printf(" tagged %s", r->match_tagname); 1052 } 1053 if (r->rtableid != -1) 1054 printf(" rtable %u", r->rtableid); 1055 if (r->divert.port) { 1056 if (PF_AZERO(&r->divert.addr, AF_INET6)) { 1057 printf(" divert-reply"); 1058 } else { 1059 /* XXX cut&paste from print_addr */ 1060 char buf[48]; 1061 1062 printf(" divert-to "); 1063 if (inet_ntop(r->af, &r->divert.addr, buf, 1064 sizeof(buf)) == NULL) 1065 printf("?"); 1066 else 1067 printf("%s", buf); 1068 printf(" port %u", ntohs(r->divert.port)); 1069 } 1070 } 1071 if (r->divert_packet.port) 1072 printf(" divert-packet port %u", ntohs(r->divert_packet.port)); 1073 1074 if (!anchor_call[0] && r->nat.addr.type != PF_ADDR_NONE && 1075 r->rule_flag & PFRULE_AFTO) { 1076 printf(" af-to %s from ", r->naf == AF_INET ? "inet" : "inet6"); 1077 print_pool(&r->nat, r->nat.proxy_port[0], 1078 r->nat.proxy_port[1], r->naf ? r->naf : r->af, 1079 PF_POOL_NAT, verbose); 1080 if (r->rdr.addr.type != PF_ADDR_NONE) { 1081 printf(" to "); 1082 print_pool(&r->rdr, r->rdr.proxy_port[0], 1083 r->rdr.proxy_port[1], r->naf ? r->naf : r->af, 1084 PF_POOL_RDR, verbose); 1085 } 1086 } else if (!anchor_call[0] && r->nat.addr.type != PF_ADDR_NONE) { 1087 printf (" nat-to "); 1088 print_pool(&r->nat, r->nat.proxy_port[0], 1089 r->nat.proxy_port[1], r->naf ? r->naf : r->af, 1090 PF_POOL_NAT, verbose); 1091 } else if (!anchor_call[0] && r->rdr.addr.type != PF_ADDR_NONE) { 1092 printf (" rdr-to "); 1093 print_pool(&r->rdr, r->rdr.proxy_port[0], 1094 r->rdr.proxy_port[1], r->af, PF_POOL_RDR, verbose); 1095 } 1096 if (r->rt) { 1097 if (r->rt == PF_ROUTETO) 1098 printf(" route-to"); 1099 else if (r->rt == PF_REPLYTO) 1100 printf(" reply-to"); 1101 else if (r->rt == PF_DUPTO) 1102 printf(" dup-to"); 1103 printf(" "); 1104 print_pool(&r->route, 0, 0, r->af, PF_POOL_ROUTE, verbose); 1105 } 1106 } 1107 1108 void 1109 print_tabledef(const char *name, int flags, int addrs, 1110 struct node_tinithead *nodes) 1111 { 1112 struct node_tinit *ti, *nti; 1113 struct node_host *h; 1114 1115 printf("table <%s>", name); 1116 if (flags & PFR_TFLAG_CONST) 1117 printf(" const"); 1118 if (flags & PFR_TFLAG_PERSIST) 1119 printf(" persist"); 1120 if (flags & PFR_TFLAG_COUNTERS) 1121 printf(" counters"); 1122 SIMPLEQ_FOREACH(ti, nodes, entries) { 1123 if (ti->file) { 1124 printf(" file \"%s\"", ti->file); 1125 continue; 1126 } 1127 printf(" {"); 1128 for (;;) { 1129 for (h = ti->host; h != NULL; h = h->next) { 1130 printf(h->not ? " !" : " "); 1131 print_addr(&h->addr, h->af, 0); 1132 if (h->ifname) 1133 printf("@%s", h->ifname); 1134 } 1135 nti = SIMPLEQ_NEXT(ti, entries); 1136 if (nti != NULL && nti->file == NULL) 1137 ti = nti; /* merge lists */ 1138 else 1139 break; 1140 } 1141 printf(" }"); 1142 } 1143 if (addrs && SIMPLEQ_EMPTY(nodes)) 1144 printf(" { }"); 1145 printf("\n"); 1146 } 1147 1148 int 1149 parse_flags(char *s) 1150 { 1151 char *p, *q; 1152 u_int8_t f = 0; 1153 1154 for (p = s; *p; p++) { 1155 if ((q = strchr(tcpflags, *p)) == NULL) 1156 return -1; 1157 else 1158 f |= 1 << (q - tcpflags); 1159 } 1160 return (f ? f : PF_TH_ALL); 1161 } 1162 1163 void 1164 set_ipmask(struct node_host *h, u_int8_t b) 1165 { 1166 struct pf_addr *m, *n; 1167 int i, j = 0; 1168 1169 m = &h->addr.v.a.mask; 1170 memset(m, 0, sizeof(*m)); 1171 1172 while (b >= 32) { 1173 m->addr32[j++] = 0xffffffff; 1174 b -= 32; 1175 } 1176 for (i = 31; i > 31-b; --i) 1177 m->addr32[j] |= (1 << i); 1178 if (b) 1179 m->addr32[j] = htonl(m->addr32[j]); 1180 1181 /* Mask off bits of the address that will never be used. */ 1182 n = &h->addr.v.a.addr; 1183 if (h->addr.type == PF_ADDR_ADDRMASK) 1184 for (i = 0; i < 4; i++) 1185 n->addr32[i] = n->addr32[i] & m->addr32[i]; 1186 } 1187 1188 int 1189 check_netmask(struct node_host *h, sa_family_t af) 1190 { 1191 struct node_host *n = NULL; 1192 struct pf_addr *m; 1193 1194 for (n = h; n != NULL; n = n->next) { 1195 if (h->addr.type == PF_ADDR_TABLE) 1196 continue; 1197 m = &h->addr.v.a.mask; 1198 /* fix up netmask for dynaddr */ 1199 if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL && 1200 unmask(m, AF_INET6) > 32) 1201 set_ipmask(n, 32); 1202 /* netmasks > 32 bit are invalid on v4 */ 1203 if (af == AF_INET && 1204 (m->addr32[1] || m->addr32[2] || m->addr32[3])) { 1205 fprintf(stderr, "netmask %u invalid for IPv4 address\n", 1206 unmask(m, AF_INET6)); 1207 return (1); 1208 } 1209 } 1210 return (0); 1211 } 1212 1213 /* interface lookup routines */ 1214 1215 struct node_host *iftab; 1216 1217 void 1218 ifa_load(void) 1219 { 1220 struct ifaddrs *ifap, *ifa; 1221 struct node_host *n = NULL, *h = NULL; 1222 1223 if (getifaddrs(&ifap) < 0) 1224 err(1, "getifaddrs"); 1225 1226 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1227 if (!(ifa->ifa_addr->sa_family == AF_INET || 1228 ifa->ifa_addr->sa_family == AF_INET6 || 1229 ifa->ifa_addr->sa_family == AF_LINK)) 1230 continue; 1231 n = calloc(1, sizeof(struct node_host)); 1232 if (n == NULL) 1233 err(1, "address: calloc"); 1234 n->af = ifa->ifa_addr->sa_family; 1235 n->ifa_flags = ifa->ifa_flags; 1236 #ifdef __KAME__ 1237 if (n->af == AF_INET6 && 1238 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) 1239 ifa->ifa_addr)->sin6_addr) && 1240 ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 1241 0) { 1242 struct sockaddr_in6 *sin6; 1243 1244 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 1245 sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | 1246 sin6->sin6_addr.s6_addr[3]; 1247 sin6->sin6_addr.s6_addr[2] = 0; 1248 sin6->sin6_addr.s6_addr[3] = 0; 1249 } 1250 #endif 1251 n->ifindex = 0; 1252 if (n->af == AF_INET) { 1253 memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *) 1254 ifa->ifa_addr)->sin_addr.s_addr, 1255 sizeof(struct in_addr)); 1256 memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *) 1257 ifa->ifa_netmask)->sin_addr.s_addr, 1258 sizeof(struct in_addr)); 1259 if (ifa->ifa_broadaddr != NULL) 1260 memcpy(&n->bcast, &((struct sockaddr_in *) 1261 ifa->ifa_broadaddr)->sin_addr.s_addr, 1262 sizeof(struct in_addr)); 1263 if (ifa->ifa_dstaddr != NULL) 1264 memcpy(&n->peer, &((struct sockaddr_in *) 1265 ifa->ifa_dstaddr)->sin_addr.s_addr, 1266 sizeof(struct in_addr)); 1267 } else if (n->af == AF_INET6) { 1268 memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) 1269 ifa->ifa_addr)->sin6_addr.s6_addr, 1270 sizeof(struct in6_addr)); 1271 memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *) 1272 ifa->ifa_netmask)->sin6_addr.s6_addr, 1273 sizeof(struct in6_addr)); 1274 if (ifa->ifa_broadaddr != NULL) 1275 memcpy(&n->bcast, &((struct sockaddr_in6 *) 1276 ifa->ifa_broadaddr)->sin6_addr.s6_addr, 1277 sizeof(struct in6_addr)); 1278 if (ifa->ifa_dstaddr != NULL) 1279 memcpy(&n->peer, &((struct sockaddr_in6 *) 1280 ifa->ifa_dstaddr)->sin6_addr.s6_addr, 1281 sizeof(struct in6_addr)); 1282 n->ifindex = ((struct sockaddr_in6 *) 1283 ifa->ifa_addr)->sin6_scope_id; 1284 } 1285 if ((n->ifname = strdup(ifa->ifa_name)) == NULL) 1286 err(1, "ifa_load: strdup"); 1287 n->next = NULL; 1288 n->tail = n; 1289 if (h == NULL) 1290 h = n; 1291 else { 1292 h->tail->next = n; 1293 h->tail = n; 1294 } 1295 } 1296 1297 iftab = h; 1298 freeifaddrs(ifap); 1299 } 1300 1301 struct node_host * 1302 ifa_exists(const char *ifa_name) 1303 { 1304 struct node_host *n; 1305 struct ifgroupreq ifgr; 1306 int s; 1307 1308 if (iftab == NULL) 1309 ifa_load(); 1310 1311 /* check whether this is a group */ 1312 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 1313 err(1, "socket"); 1314 bzero(&ifgr, sizeof(ifgr)); 1315 strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); 1316 if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) { 1317 /* fake a node_host */ 1318 if ((n = calloc(1, sizeof(*n))) == NULL) 1319 err(1, "calloc"); 1320 if ((n->ifname = strdup(ifa_name)) == NULL) 1321 err(1, "strdup"); 1322 close(s); 1323 return (n); 1324 } 1325 close(s); 1326 1327 for (n = iftab; n; n = n->next) { 1328 if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) 1329 return (n); 1330 } 1331 1332 return (NULL); 1333 } 1334 1335 struct node_host * 1336 ifa_grouplookup(const char *ifa_name, int flags) 1337 { 1338 struct ifg_req *ifg; 1339 struct ifgroupreq ifgr; 1340 int s, len; 1341 struct node_host *n, *h = NULL; 1342 1343 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 1344 err(1, "socket"); 1345 bzero(&ifgr, sizeof(ifgr)); 1346 strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); 1347 if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { 1348 close(s); 1349 return (NULL); 1350 } 1351 1352 len = ifgr.ifgr_len; 1353 if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) 1354 err(1, "calloc"); 1355 if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) 1356 err(1, "SIOCGIFGMEMB"); 1357 1358 for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); 1359 ifg++) { 1360 len -= sizeof(struct ifg_req); 1361 if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL) 1362 continue; 1363 if (h == NULL) 1364 h = n; 1365 else { 1366 h->tail->next = n; 1367 h->tail = n->tail; 1368 } 1369 } 1370 free(ifgr.ifgr_groups); 1371 close(s); 1372 1373 return (h); 1374 } 1375 1376 struct node_host * 1377 ifa_lookup(const char *ifa_name, int flags) 1378 { 1379 struct node_host *p = NULL, *h = NULL, *n = NULL; 1380 int got4 = 0, got6 = 0; 1381 const char *last_if = NULL; 1382 1383 if ((h = ifa_grouplookup(ifa_name, flags)) != NULL) 1384 return (h); 1385 1386 if (!strncmp(ifa_name, "self", IFNAMSIZ)) 1387 ifa_name = NULL; 1388 1389 if (iftab == NULL) 1390 ifa_load(); 1391 1392 for (p = iftab; p; p = p->next) { 1393 if (ifa_skip_if(ifa_name, p)) 1394 continue; 1395 if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET) 1396 continue; 1397 if ((flags & PFI_AFLAG_BROADCAST) && 1398 !(p->ifa_flags & IFF_BROADCAST)) 1399 continue; 1400 if ((flags & PFI_AFLAG_PEER) && 1401 !(p->ifa_flags & IFF_POINTOPOINT)) 1402 continue; 1403 if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0) 1404 continue; 1405 if (last_if == NULL || strcmp(last_if, p->ifname)) 1406 got4 = got6 = 0; 1407 last_if = p->ifname; 1408 if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4) 1409 continue; 1410 if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6) 1411 continue; 1412 if (p->af == AF_INET) 1413 got4 = 1; 1414 else 1415 got6 = 1; 1416 n = calloc(1, sizeof(struct node_host)); 1417 if (n == NULL) 1418 err(1, "address: calloc"); 1419 n->af = p->af; 1420 if (flags & PFI_AFLAG_BROADCAST) 1421 memcpy(&n->addr.v.a.addr, &p->bcast, 1422 sizeof(struct pf_addr)); 1423 else if (flags & PFI_AFLAG_PEER) 1424 memcpy(&n->addr.v.a.addr, &p->peer, 1425 sizeof(struct pf_addr)); 1426 else 1427 memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, 1428 sizeof(struct pf_addr)); 1429 if (flags & PFI_AFLAG_NETWORK) 1430 set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); 1431 else { 1432 if (n->af == AF_INET) { 1433 if (p->ifa_flags & IFF_LOOPBACK && 1434 p->ifa_flags & IFF_LINK1) 1435 memcpy(&n->addr.v.a.mask, 1436 &p->addr.v.a.mask, 1437 sizeof(struct pf_addr)); 1438 else 1439 set_ipmask(n, 32); 1440 } else 1441 set_ipmask(n, 128); 1442 } 1443 n->ifindex = p->ifindex; 1444 1445 n->next = NULL; 1446 n->tail = n; 1447 if (h == NULL) 1448 h = n; 1449 else { 1450 h->tail->next = n; 1451 h->tail = n; 1452 } 1453 } 1454 return (h); 1455 } 1456 1457 int 1458 ifa_skip_if(const char *filter, struct node_host *p) 1459 { 1460 int n; 1461 1462 if (p->af != AF_INET && p->af != AF_INET6) 1463 return (1); 1464 if (filter == NULL || !*filter) 1465 return (0); 1466 if (!strcmp(p->ifname, filter)) 1467 return (0); /* exact match */ 1468 n = strlen(filter); 1469 if (n < 1 || n >= IFNAMSIZ) 1470 return (1); /* sanity check */ 1471 if (filter[n-1] >= '0' && filter[n-1] <= '9') 1472 return (1); /* only do exact match in that case */ 1473 if (strncmp(p->ifname, filter, n)) 1474 return (1); /* prefix doesn't match */ 1475 return (p->ifname[n] < '0' || p->ifname[n] > '9'); 1476 } 1477 1478 struct node_host * 1479 host(const char *s) 1480 { 1481 struct node_host *h = NULL, *n; 1482 int mask = -1, v4mask = 32, v6mask = 128, cont = 1; 1483 char *p, *q, *r, *ps, *if_name; 1484 1485 if ((ps = strdup(s)) == NULL) 1486 err(1, "host: strdup"); 1487 1488 if ((if_name = strrchr(ps, '@')) != NULL) { 1489 if_name[0] = '\0'; 1490 if_name++; 1491 } 1492 1493 if ((p = strrchr(ps, '/')) != NULL) { 1494 if ((r = strdup(ps)) == NULL) 1495 err(1, "host: strdup"); 1496 mask = strtol(p+1, &q, 0); 1497 if (!q || *q || mask > 128 || q == (p+1)) { 1498 fprintf(stderr, "invalid netmask '%s'\n", p); 1499 free(r); 1500 free(ps); 1501 return (NULL); 1502 } 1503 p[0] = '\0'; 1504 v4mask = v6mask = mask; 1505 } else 1506 r = ps; 1507 1508 /* interface with this name exists? */ 1509 if (cont && (h = host_if(ps, mask)) != NULL) 1510 cont = 0; 1511 1512 /* IPv4 address? */ 1513 if (cont && (h = host_v4(r, mask)) != NULL) 1514 cont = 0; 1515 if (r != ps) 1516 free(r); 1517 1518 /* IPv6 address? */ 1519 if (cont && (h = host_v6(ps, v6mask)) != NULL) 1520 cont = 0; 1521 1522 /* dns lookup */ 1523 if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL) 1524 cont = 0; 1525 1526 if (if_name && if_name[0]) 1527 for (n = h; n != NULL; n = n->next) 1528 if ((n->ifname = strdup(if_name)) == NULL) 1529 err(1, "host: strdup"); 1530 1531 free(ps); /* after we copy the name out */ 1532 if (h == NULL || cont == 1) { 1533 fprintf(stderr, "no IP address found for %s\n", s); 1534 return (NULL); 1535 } 1536 for (n = h; n != NULL; n = n->next) { 1537 n->addr.type = PF_ADDR_ADDRMASK; 1538 n->weight = 0; 1539 } 1540 return (h); 1541 } 1542 1543 struct node_host * 1544 host_if(const char *s, int mask) 1545 { 1546 struct node_host *n, *h = NULL; 1547 char *p, *ps; 1548 int flags = 0; 1549 1550 if ((ps = strdup(s)) == NULL) 1551 err(1, "host_if: strdup"); 1552 while ((p = strrchr(ps, ':')) != NULL) { 1553 if (!strcmp(p+1, "network")) 1554 flags |= PFI_AFLAG_NETWORK; 1555 else if (!strcmp(p+1, "broadcast")) 1556 flags |= PFI_AFLAG_BROADCAST; 1557 else if (!strcmp(p+1, "peer")) 1558 flags |= PFI_AFLAG_PEER; 1559 else if (!strcmp(p+1, "0")) 1560 flags |= PFI_AFLAG_NOALIAS; 1561 else { 1562 free(ps); 1563 return (NULL); 1564 } 1565 *p = '\0'; 1566 } 1567 if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */ 1568 fprintf(stderr, "illegal combination of interface modifiers\n"); 1569 free(ps); 1570 return (NULL); 1571 } 1572 if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) { 1573 fprintf(stderr, "network or broadcast lookup, but " 1574 "extra netmask given\n"); 1575 free(ps); 1576 return (NULL); 1577 } 1578 if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { 1579 /* interface with this name exists */ 1580 h = ifa_lookup(ps, flags); 1581 for (n = h; n != NULL && mask > -1; n = n->next) 1582 set_ipmask(n, mask); 1583 } 1584 1585 free(ps); 1586 return (h); 1587 } 1588 1589 struct node_host * 1590 host_v4(const char *s, int mask) 1591 { 1592 struct node_host *h = NULL; 1593 struct in_addr ina; 1594 int bits = 32; 1595 1596 memset(&ina, 0, sizeof(struct in_addr)); 1597 if (strrchr(s, '/') != NULL) { 1598 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) 1599 return (NULL); 1600 } else { 1601 if (inet_pton(AF_INET, s, &ina) != 1) 1602 return (NULL); 1603 } 1604 1605 h = calloc(1, sizeof(struct node_host)); 1606 if (h == NULL) 1607 err(1, "address: calloc"); 1608 h->ifname = NULL; 1609 h->af = AF_INET; 1610 h->addr.v.a.addr.addr32[0] = ina.s_addr; 1611 set_ipmask(h, bits); 1612 h->next = NULL; 1613 h->tail = h; 1614 1615 return (h); 1616 } 1617 1618 struct node_host * 1619 host_v6(const char *s, int mask) 1620 { 1621 struct addrinfo hints, *res; 1622 struct node_host *h = NULL; 1623 1624 memset(&hints, 0, sizeof(hints)); 1625 hints.ai_family = AF_INET6; 1626 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 1627 hints.ai_flags = AI_NUMERICHOST; 1628 if (getaddrinfo(s, "0", &hints, &res) == 0) { 1629 h = calloc(1, sizeof(struct node_host)); 1630 if (h == NULL) 1631 err(1, "address: calloc"); 1632 h->ifname = NULL; 1633 h->af = AF_INET6; 1634 memcpy(&h->addr.v.a.addr, 1635 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 1636 sizeof(h->addr.v.a.addr)); 1637 h->ifindex = 1638 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 1639 set_ipmask(h, mask); 1640 freeaddrinfo(res); 1641 h->next = NULL; 1642 h->tail = h; 1643 } 1644 1645 return (h); 1646 } 1647 1648 struct node_host * 1649 host_dns(const char *s, int v4mask, int v6mask) 1650 { 1651 struct addrinfo hints, *res0, *res; 1652 struct node_host *n, *h = NULL; 1653 int error, noalias = 0; 1654 int got4 = 0, got6 = 0; 1655 char *p, *ps; 1656 1657 if ((ps = strdup(s)) == NULL) 1658 err(1, "host_dns: strdup"); 1659 if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) { 1660 noalias = 1; 1661 *p = '\0'; 1662 } 1663 memset(&hints, 0, sizeof(hints)); 1664 hints.ai_family = PF_UNSPEC; 1665 hints.ai_socktype = SOCK_STREAM; /* DUMMY */ 1666 error = getaddrinfo(ps, NULL, &hints, &res0); 1667 if (error) { 1668 free(ps); 1669 return (h); 1670 } 1671 1672 for (res = res0; res; res = res->ai_next) { 1673 if (res->ai_family != AF_INET && 1674 res->ai_family != AF_INET6) 1675 continue; 1676 if (noalias) { 1677 if (res->ai_family == AF_INET) { 1678 if (got4) 1679 continue; 1680 got4 = 1; 1681 } else { 1682 if (got6) 1683 continue; 1684 got6 = 1; 1685 } 1686 } 1687 n = calloc(1, sizeof(struct node_host)); 1688 if (n == NULL) 1689 err(1, "host_dns: calloc"); 1690 n->ifname = NULL; 1691 n->af = res->ai_family; 1692 if (res->ai_family == AF_INET) { 1693 memcpy(&n->addr.v.a.addr, 1694 &((struct sockaddr_in *) 1695 res->ai_addr)->sin_addr.s_addr, 1696 sizeof(struct in_addr)); 1697 set_ipmask(n, v4mask); 1698 } else { 1699 memcpy(&n->addr.v.a.addr, 1700 &((struct sockaddr_in6 *) 1701 res->ai_addr)->sin6_addr.s6_addr, 1702 sizeof(struct in6_addr)); 1703 n->ifindex = 1704 ((struct sockaddr_in6 *) 1705 res->ai_addr)->sin6_scope_id; 1706 set_ipmask(n, v6mask); 1707 } 1708 n->next = NULL; 1709 n->tail = n; 1710 if (h == NULL) 1711 h = n; 1712 else { 1713 h->tail->next = n; 1714 h->tail = n; 1715 } 1716 } 1717 freeaddrinfo(res0); 1718 free(ps); 1719 1720 return (h); 1721 } 1722 1723 /* 1724 * convert a hostname to a list of addresses and put them in the given buffer. 1725 * test: 1726 * if set to 1, only simple addresses are accepted (no netblock, no "!"). 1727 */ 1728 int 1729 append_addr(struct pfr_buffer *b, char *s, int test) 1730 { 1731 static int previous = 0; 1732 static int expect = 0; 1733 struct pfr_addr *a; 1734 struct node_host *h, *n; 1735 char *r; 1736 const char *errstr; 1737 int rv, not = 0, i = 0; 1738 u_int16_t weight; 1739 1740 /* skip weight if given */ 1741 if (strcmp(s, "weight") == 0) { 1742 expect = 1; 1743 return (1); /* expecting further call */ 1744 } 1745 1746 /* check if previous host is set */ 1747 if (expect) { 1748 /* parse and append load balancing weight */ 1749 weight = strtonum(s, 1, USHRT_MAX, &errstr); 1750 if (errstr) { 1751 fprintf(stderr, "failed to convert weight %s\n", s); 1752 return (-1); 1753 } 1754 if (previous != -1) { 1755 PFRB_FOREACH(a, b) { 1756 if (++i >= previous) { 1757 a->pfra_weight = weight; 1758 a->pfra_type = PFRKE_COST; 1759 } 1760 } 1761 } 1762 1763 expect = 0; 1764 return (0); 1765 } 1766 1767 for (r = s; *r == '!'; r++) 1768 not = !not; 1769 if ((n = host(r)) == NULL) { 1770 errno = 0; 1771 return (-1); 1772 } 1773 rv = append_addr_host(b, n, test, not); 1774 previous = b->pfrb_size; 1775 do { 1776 h = n; 1777 n = n->next; 1778 free(h); 1779 } while (n != NULL); 1780 return (rv); 1781 } 1782 1783 /* 1784 * same as previous function, but with a pre-parsed input and the ability 1785 * to "negate" the result. Does not free the node_host list. 1786 * not: 1787 * setting it to 1 is equivalent to adding "!" in front of parameter s. 1788 */ 1789 int 1790 append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not) 1791 { 1792 int bits; 1793 struct pfr_addr addr; 1794 1795 do { 1796 bzero(&addr, sizeof(addr)); 1797 addr.pfra_not = n->not ^ not; 1798 addr.pfra_af = n->af; 1799 addr.pfra_net = unmask(&n->addr.v.a.mask, n->af); 1800 if (n->ifname) { 1801 if (strlcpy(addr.pfra_ifname, n->ifname, 1802 sizeof(addr.pfra_ifname)) >= sizeof(addr.pfra_ifname)) 1803 errx(1, "append_addr_host: strlcpy"); 1804 addr.pfra_type = PFRKE_ROUTE; 1805 } 1806 if (n->weight > 0) { 1807 addr.pfra_weight = n->weight; 1808 addr.pfra_type = PFRKE_COST; 1809 } 1810 switch (n->af) { 1811 case AF_INET: 1812 addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0]; 1813 bits = 32; 1814 break; 1815 case AF_INET6: 1816 memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6, 1817 sizeof(struct in6_addr)); 1818 bits = 128; 1819 break; 1820 default: 1821 errno = EINVAL; 1822 return (-1); 1823 } 1824 if ((test && (not || addr.pfra_net != bits)) || 1825 addr.pfra_net > bits) { 1826 errno = EINVAL; 1827 return (-1); 1828 } 1829 if (pfr_buf_add(b, &addr)) 1830 return (-1); 1831 } while ((n = n->next) != NULL); 1832 1833 return (0); 1834 } 1835 1836 int 1837 pfctl_add_trans(struct pfr_buffer *buf, int type, const char *anchor) 1838 { 1839 struct pfioc_trans_e trans; 1840 1841 bzero(&trans, sizeof(trans)); 1842 trans.type = type; 1843 if (strlcpy(trans.anchor, anchor, 1844 sizeof(trans.anchor)) >= sizeof(trans.anchor)) 1845 errx(1, "pfctl_add_trans: strlcpy"); 1846 1847 return pfr_buf_add(buf, &trans); 1848 } 1849 1850 u_int32_t 1851 pfctl_get_ticket(struct pfr_buffer *buf, int type, const char *anchor) 1852 { 1853 struct pfioc_trans_e *p; 1854 1855 PFRB_FOREACH(p, buf) 1856 if (type == p->type && !strcmp(anchor, p->anchor)) 1857 return (p->ticket); 1858 errx(1, "pfctl_get_ticket: assertion failed"); 1859 } 1860 1861 int 1862 pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from) 1863 { 1864 struct pfioc_trans trans; 1865 1866 bzero(&trans, sizeof(trans)); 1867 trans.size = buf->pfrb_size - from; 1868 trans.esize = sizeof(struct pfioc_trans_e); 1869 trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from; 1870 return ioctl(dev, cmd, &trans); 1871 } 1872