1 /* $OpenBSD: pfe_filter.c,v 1.38 2009/04/24 14:20:24 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/socket.h> 22 #include <sys/ioctl.h> 23 24 #include <net/if.h> 25 #include <net/pfvar.h> 26 #include <netinet/in.h> 27 #include <arpa/inet.h> 28 29 #include <limits.h> 30 #include <fcntl.h> 31 #include <event.h> 32 #include <string.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <errno.h> 36 37 #include <openssl/ssl.h> 38 39 #include "relayd.h" 40 41 struct pfdata { 42 int dev; 43 struct pf_anchor *anchor; 44 struct pfioc_trans pft[PF_RULESET_MAX]; 45 struct pfioc_trans_e pfte[PF_RULESET_MAX]; 46 u_int8_t pfused; 47 }; 48 49 int transaction_init(struct relayd *, const char *); 50 int transaction_commit(struct relayd *); 51 void kill_tables(struct relayd *); 52 int kill_srcnodes(struct relayd *, struct table *); 53 54 void 55 init_filter(struct relayd *env) 56 { 57 struct pf_status status; 58 59 if (!(env->sc_flags & F_NEEDPF)) 60 return; 61 62 if ((env->sc_pf = calloc(1, sizeof(*(env->sc_pf)))) == NULL) 63 fatal("calloc"); 64 if ((env->sc_pf->dev = open(PF_SOCKET, O_RDWR)) == -1) 65 fatal("init_filter: cannot open pf socket"); 66 if (ioctl(env->sc_pf->dev, DIOCGETSTATUS, &status) == -1) 67 fatal("init_filter: DIOCGETSTATUS"); 68 if (!status.running) 69 fatalx("init_filter: pf is disabled"); 70 log_debug("init_filter: filter init done"); 71 } 72 73 void 74 init_tables(struct relayd *env) 75 { 76 int i; 77 struct rdr *rdr; 78 struct pfr_table *tables; 79 struct pfioc_table io; 80 81 if (!(env->sc_flags & F_NEEDPF)) 82 return; 83 84 if ((tables = calloc(env->sc_rdrcount, sizeof(*tables))) == NULL) 85 fatal("calloc"); 86 i = 0; 87 88 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 89 if (strlcpy(tables[i].pfrt_anchor, RELAYD_ANCHOR "/", 90 sizeof(tables[i].pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 91 goto toolong; 92 if (strlcat(tables[i].pfrt_anchor, rdr->conf.name, 93 sizeof(tables[i].pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 94 goto toolong; 95 if (strlcpy(tables[i].pfrt_name, rdr->conf.name, 96 sizeof(tables[i].pfrt_name)) >= 97 sizeof(tables[i].pfrt_name)) 98 goto toolong; 99 tables[i].pfrt_flags |= PFR_TFLAG_PERSIST; 100 i++; 101 } 102 if (i != env->sc_rdrcount) 103 fatalx("init_tables: table count modified"); 104 105 memset(&io, 0, sizeof(io)); 106 io.pfrio_size = env->sc_rdrcount; 107 io.pfrio_esize = sizeof(*tables); 108 io.pfrio_buffer = tables; 109 110 if (ioctl(env->sc_pf->dev, DIOCRADDTABLES, &io) == -1) 111 fatal("init_tables: cannot create tables"); 112 log_debug("init_tables: created %d tables", io.pfrio_nadd); 113 114 free(tables); 115 116 if (io.pfrio_nadd == env->sc_rdrcount) 117 return; 118 119 /* 120 * clear all tables, since some already existed 121 */ 122 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) 123 flush_table(env, rdr); 124 125 return; 126 127 toolong: 128 fatal("init_tables: name too long"); 129 } 130 131 void 132 kill_tables(struct relayd *env) 133 { 134 struct pfioc_table io; 135 struct rdr *rdr; 136 int cnt = 0; 137 138 if (!(env->sc_flags & F_NEEDPF)) 139 return; 140 141 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 142 memset(&io, 0, sizeof(io)); 143 if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/", 144 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 145 goto toolong; 146 if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name, 147 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 148 goto toolong; 149 if (ioctl(env->sc_pf->dev, DIOCRCLRTABLES, &io) == -1) 150 fatal("kill_tables: ioctl failed"); 151 cnt += io.pfrio_ndel; 152 } 153 log_debug("kill_tables: deleted %d tables", cnt); 154 return; 155 156 toolong: 157 fatal("kill_tables: name too long"); 158 } 159 160 void 161 sync_table(struct relayd *env, struct rdr *rdr, struct table *table) 162 { 163 int i, cnt = 0; 164 struct pfioc_table io; 165 struct pfr_addr *addlist; 166 struct sockaddr_in *sain; 167 struct sockaddr_in6 *sain6; 168 struct host *host; 169 170 if (!(env->sc_flags & F_NEEDPF)) 171 return; 172 173 if (table == NULL) 174 return; 175 176 if (table->up == 0) { 177 flush_table(env, rdr); 178 return; 179 } 180 181 if ((addlist = calloc(table->up, sizeof(*addlist))) == NULL) 182 fatal("calloc"); 183 184 memset(&io, 0, sizeof(io)); 185 io.pfrio_esize = sizeof(struct pfr_addr); 186 io.pfrio_size = table->up; 187 io.pfrio_size2 = 0; 188 io.pfrio_buffer = addlist; 189 if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/", 190 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 191 goto toolong; 192 if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name, 193 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 194 goto toolong; 195 if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name, 196 sizeof(io.pfrio_table.pfrt_name)) >= 197 sizeof(io.pfrio_table.pfrt_name)) 198 goto toolong; 199 200 i = 0; 201 TAILQ_FOREACH(host, &table->hosts, entry) { 202 if (host->up != HOST_UP) 203 continue; 204 memset(&(addlist[i]), 0, sizeof(addlist[i])); 205 switch (host->conf.ss.ss_family) { 206 case AF_INET: 207 sain = (struct sockaddr_in *)&host->conf.ss; 208 addlist[i].pfra_af = AF_INET; 209 memcpy(&(addlist[i].pfra_ip4addr), &sain->sin_addr, 210 sizeof(sain->sin_addr)); 211 addlist[i].pfra_net = 32; 212 break; 213 case AF_INET6: 214 sain6 = (struct sockaddr_in6 *)&host->conf.ss; 215 addlist[i].pfra_af = AF_INET6; 216 memcpy(&(addlist[i].pfra_ip6addr), &sain6->sin6_addr, 217 sizeof(sain6->sin6_addr)); 218 addlist[i].pfra_net = 128; 219 break; 220 default: 221 fatalx("sync_table: unknown address family"); 222 break; 223 } 224 i++; 225 } 226 if (i != table->up) 227 fatalx("sync_table: desynchronized"); 228 229 if (ioctl(env->sc_pf->dev, DIOCRSETADDRS, &io) == -1) 230 fatal("sync_table: cannot set address list"); 231 if (rdr->conf.flags & F_STICKY) 232 cnt = kill_srcnodes(env, table); 233 free(addlist); 234 235 if (env->sc_opts & RELAYD_OPT_LOGUPDATE) 236 log_info("table %s: %d added, %d deleted, " 237 "%d changed, %d killed", io.pfrio_table.pfrt_name, 238 io.pfrio_nadd, io.pfrio_ndel, io.pfrio_nchange, cnt); 239 return; 240 241 toolong: 242 fatal("sync_table: name too long"); 243 } 244 245 int 246 kill_srcnodes(struct relayd *env, struct table *table) 247 { 248 struct host *host; 249 struct pfioc_src_node_kill psnk; 250 int cnt = 0; 251 struct sockaddr_in *sain; 252 struct sockaddr_in6 *sain6; 253 254 bzero(&psnk, sizeof(psnk)); 255 256 /* Only match the destination address, source mask will be zero */ 257 memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, 258 sizeof(psnk.psnk_dst.addr.v.a.mask)); 259 260 TAILQ_FOREACH(host, &table->hosts, entry) { 261 if (host->up != HOST_DOWN) 262 continue; 263 264 switch (host->conf.ss.ss_family) { 265 case AF_INET: 266 sain = (struct sockaddr_in *)&host->conf.ss; 267 bcopy(&sain->sin_addr, 268 &psnk.psnk_dst.addr.v.a.addr.v4, 269 sizeof(psnk.psnk_dst.addr.v.a.addr.v4)); 270 break; 271 case AF_INET6: 272 sain6 = (struct sockaddr_in6 *)&host->conf.ss; 273 bcopy(&sain6->sin6_addr, 274 &psnk.psnk_dst.addr.v.a.addr.v6, 275 sizeof(psnk.psnk_dst.addr.v.a.addr.v6)); 276 break; 277 default: 278 fatalx("kill_srcnodes: unknown address family"); 279 break; 280 } 281 282 psnk.psnk_af = host->conf.ss.ss_family; 283 psnk.psnk_killed = 0; 284 285 if (ioctl(env->sc_pf->dev, 286 DIOCKILLSRCNODES, &psnk) == -1) 287 fatal("kill_srcnodes: cannot kill src nodes"); 288 cnt += psnk.psnk_killed; 289 } 290 291 return (cnt); 292 } 293 294 void 295 flush_table(struct relayd *env, struct rdr *rdr) 296 { 297 struct pfioc_table io; 298 299 if (!(env->sc_flags & F_NEEDPF)) 300 return; 301 302 memset(&io, 0, sizeof(io)); 303 if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/", 304 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 305 goto toolong; 306 if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name, 307 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 308 goto toolong; 309 if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name, 310 sizeof(io.pfrio_table.pfrt_name)) >= 311 sizeof(io.pfrio_table.pfrt_name)) 312 goto toolong; 313 if (ioctl(env->sc_pf->dev, DIOCRCLRADDRS, &io) == -1) 314 fatal("flush_table: cannot flush table addresses"); 315 316 io.pfrio_esize = sizeof(io.pfrio_table); 317 io.pfrio_size = 1; 318 io.pfrio_buffer = &io.pfrio_table; 319 if (ioctl(env->sc_pf->dev, DIOCRCLRTSTATS, &io) == -1) 320 fatal("flush_table: cannot flush table stats"); 321 322 log_debug("flush_table: flushed table %s", rdr->conf.name); 323 return; 324 325 toolong: 326 fatal("flush_table: name too long"); 327 } 328 329 int 330 transaction_init(struct relayd *env, const char *anchor) 331 { 332 int i; 333 334 for (i = 0; i < PF_RULESET_MAX; i++) { 335 env->sc_pf->pft[i].size = 1; 336 env->sc_pf->pft[i].esize = sizeof(env->sc_pf->pfte[i]); 337 env->sc_pf->pft[i].array = &env->sc_pf->pfte[i]; 338 339 bzero(&env->sc_pf->pfte[i], sizeof(env->sc_pf->pfte[i])); 340 (void)strlcpy(env->sc_pf->pfte[i].anchor, 341 anchor, PF_ANCHOR_NAME_SIZE); 342 env->sc_pf->pfte[i].rs_num = i; 343 344 if (ioctl(env->sc_pf->dev, DIOCXBEGIN, 345 &env->sc_pf->pft[i]) == -1) 346 return (-1); 347 } 348 return (0); 349 } 350 351 int 352 transaction_commit(struct relayd *env) 353 { 354 int i; 355 356 for (i = 0; i < PF_RULESET_MAX; i++) { 357 if (ioctl(env->sc_pf->dev, DIOCXCOMMIT, 358 &env->sc_pf->pft[i]) == -1) 359 return (-1); 360 } 361 return (0); 362 } 363 364 void 365 sync_ruleset(struct relayd *env, struct rdr *rdr, int enable) 366 { 367 struct pfioc_rule rio; 368 struct pfioc_pooladdr pio; 369 struct sockaddr_in *sain; 370 struct sockaddr_in6 *sain6; 371 struct address *address; 372 char anchor[PF_ANCHOR_NAME_SIZE]; 373 int rs; 374 struct table *t = rdr->table; 375 376 if (!(env->sc_flags & F_NEEDPF)) 377 return; 378 379 bzero(anchor, sizeof(anchor)); 380 if (strlcpy(anchor, RELAYD_ANCHOR "/", sizeof(anchor)) >= 381 PF_ANCHOR_NAME_SIZE) 382 goto toolong; 383 if (strlcat(anchor, rdr->conf.name, sizeof(anchor)) >= 384 PF_ANCHOR_NAME_SIZE) 385 goto toolong; 386 if (transaction_init(env, anchor) == -1) { 387 log_warn("sync_ruleset: transaction init failed"); 388 return; 389 } 390 391 if (!enable) { 392 if (transaction_commit(env) == -1) 393 log_warn("sync_ruleset: " 394 "remove rules transaction failed"); 395 else 396 log_debug("sync_ruleset: rules removed"); 397 return; 398 } 399 400 TAILQ_FOREACH(address, &rdr->virts, entry) { 401 memset(&rio, 0, sizeof(rio)); 402 memset(&pio, 0, sizeof(pio)); 403 (void)strlcpy(rio.anchor, anchor, sizeof(rio.anchor)); 404 405 switch (t->conf.fwdmode) { 406 case FWD_NORMAL: 407 /* traditional redirection in the rdr-anchor */ 408 rs = PF_RULESET_RDR; 409 rio.rule.action = PF_RDR; 410 break; 411 case FWD_ROUTE: 412 /* re-route with pf for DSR (direct server return) */ 413 rs = PF_RULESET_FILTER; 414 rio.rule.action = PF_PASS; 415 rio.rule.rt = PF_ROUTETO; 416 rio.rule.direction = PF_IN; 417 rio.rule.quick = 1; /* force first match */ 418 419 /* Use sloppy state handling for half connections */ 420 rio.rule.keep_state = PF_STATE_NORMAL; 421 rio.rule.rule_flag = PFRULE_STATESLOPPY; 422 break; 423 default: 424 fatalx("sync_ruleset: invalid forward mode"); 425 /* NOTREACHED */ 426 } 427 428 rio.ticket = env->sc_pf->pfte[rs].ticket; 429 if (ioctl(env->sc_pf->dev, DIOCBEGINADDRS, &pio) == -1) 430 fatal("sync_ruleset: cannot initialise address pool"); 431 432 rio.pool_ticket = pio.ticket; 433 rio.rule.af = address->ss.ss_family; 434 rio.rule.proto = address->ipproto; 435 rio.rule.src.addr.type = PF_ADDR_ADDRMASK; 436 rio.rule.dst.addr.type = PF_ADDR_ADDRMASK; 437 rio.rule.dst.port_op = address->port.op; 438 rio.rule.dst.port[0] = address->port.val[0]; 439 rio.rule.dst.port[1] = address->port.val[1]; 440 rio.rule.rtableid = -1; /* stay in the main routing table */ 441 442 if (rio.rule.proto == IPPROTO_TCP) 443 rio.rule.timeout[PFTM_TCP_ESTABLISHED] = 444 rdr->conf.timeout.tv_sec; 445 446 if (strlen(rdr->conf.tag)) 447 (void)strlcpy(rio.rule.tagname, rdr->conf.tag, 448 sizeof(rio.rule.tagname)); 449 if (strlen(address->ifname)) 450 (void)strlcpy(rio.rule.ifname, address->ifname, 451 sizeof(rio.rule.ifname)); 452 453 if (address->ss.ss_family == AF_INET) { 454 sain = (struct sockaddr_in *)&address->ss; 455 456 rio.rule.dst.addr.v.a.addr.addr32[0] = 457 sain->sin_addr.s_addr; 458 rio.rule.dst.addr.v.a.mask.addr32[0] = 0xffffffff; 459 } else { 460 sain6 = (struct sockaddr_in6 *)&address->ss; 461 462 memcpy(&rio.rule.dst.addr.v.a.addr.v6, 463 &sain6->sin6_addr.s6_addr, 464 sizeof(sain6->sin6_addr.s6_addr)); 465 memset(&rio.rule.dst.addr.v.a.mask.addr8, 0xff, 16); 466 } 467 468 pio.addr.addr.type = PF_ADDR_TABLE; 469 if (strlen(t->conf.ifname)) 470 (void)strlcpy(pio.addr.ifname, t->conf.ifname, 471 sizeof(pio.addr.ifname)); 472 if (strlcpy(pio.addr.addr.v.tblname, rdr->conf.name, 473 sizeof(pio.addr.addr.v.tblname)) >= 474 sizeof(pio.addr.addr.v.tblname)) 475 fatal("sync_ruleset: table name too long"); 476 if (ioctl(env->sc_pf->dev, DIOCADDADDR, &pio) == -1) 477 fatal("sync_ruleset: cannot add address to pool"); 478 479 if (address->port.op == PF_OP_EQ || 480 rdr->table->conf.flags & F_PORT) { 481 rio.rule.rpool.proxy_port[0] = 482 ntohs(rdr->table->conf.port); 483 rio.rule.rpool.port_op = PF_OP_EQ; 484 } 485 rio.rule.rpool.opts = PF_POOL_ROUNDROBIN; 486 if (rdr->conf.flags & F_STICKY) 487 rio.rule.rpool.opts |= PF_POOL_STICKYADDR; 488 489 if (ioctl(env->sc_pf->dev, DIOCADDRULE, &rio) == -1) 490 fatal("cannot add rule"); 491 log_debug("sync_ruleset: rule added to %sanchor \"%s\"", 492 rdr->table->conf.fwdmode == FWD_ROUTE ? 493 "" : "rdr-", anchor); 494 } 495 if (transaction_commit(env) == -1) 496 log_warn("sync_ruleset: add rules transaction failed"); 497 return; 498 499 toolong: 500 fatal("sync_ruleset: name too long"); 501 } 502 503 void 504 flush_rulesets(struct relayd *env) 505 { 506 struct rdr *rdr; 507 char anchor[PF_ANCHOR_NAME_SIZE]; 508 509 if (!(env->sc_flags & F_NEEDPF)) 510 return; 511 512 kill_tables(env); 513 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 514 if (strlcpy(anchor, RELAYD_ANCHOR "/", sizeof(anchor)) >= 515 PF_ANCHOR_NAME_SIZE) 516 goto toolong; 517 if (strlcat(anchor, rdr->conf.name, sizeof(anchor)) >= 518 PF_ANCHOR_NAME_SIZE) 519 goto toolong; 520 if (transaction_init(env, anchor) == -1 || 521 transaction_commit(env) == -1) 522 log_warn("flush_rulesets: transaction for %s/ failed", 523 RELAYD_ANCHOR); 524 } 525 if (strlcpy(anchor, RELAYD_ANCHOR, sizeof(anchor)) >= 526 PF_ANCHOR_NAME_SIZE) 527 goto toolong; 528 if (transaction_init(env, anchor) == -1 || 529 transaction_commit(env) == -1) 530 log_warn("flush_rulesets: transaction for %s failed", 531 RELAYD_ANCHOR); 532 log_debug("flush_rulesets: flushed rules"); 533 return; 534 535 toolong: 536 fatal("flush_rulesets: name too long"); 537 } 538 539 int 540 natlook(struct relayd *env, struct ctl_natlook *cnl) 541 { 542 struct pfioc_natlook pnl; 543 struct sockaddr_in *in, *out; 544 struct sockaddr_in6 *in6, *out6; 545 char ibuf[BUFSIZ], obuf[BUFSIZ]; 546 547 if (!(env->sc_flags & F_NEEDPF)) 548 return (0); 549 550 bzero(&pnl, sizeof(pnl)); 551 552 if ((pnl.af = cnl->src.ss_family) != cnl->dst.ss_family) 553 fatalx("natlook: illegal address families"); 554 switch (pnl.af) { 555 case AF_INET: 556 in = (struct sockaddr_in *)&cnl->src; 557 out = (struct sockaddr_in *)&cnl->dst; 558 bcopy(&in->sin_addr, &pnl.saddr.v4, sizeof(pnl.saddr.v4)); 559 pnl.sport = in->sin_port; 560 bcopy(&out->sin_addr, &pnl.daddr.v4, sizeof(pnl.daddr.v4)); 561 pnl.dport = out->sin_port; 562 break; 563 case AF_INET6: 564 in6 = (struct sockaddr_in6 *)&cnl->src; 565 out6 = (struct sockaddr_in6 *)&cnl->dst; 566 bcopy(&in6->sin6_addr, &pnl.saddr.v6, sizeof(pnl.saddr.v6)); 567 pnl.sport = in6->sin6_port; 568 bcopy(&out6->sin6_addr, &pnl.daddr.v6, sizeof(pnl.daddr.v6)); 569 pnl.dport = out6->sin6_port; 570 } 571 pnl.proto = cnl->proto; 572 pnl.direction = PF_IN; 573 cnl->in = 1; 574 575 if (ioctl(env->sc_pf->dev, DIOCNATLOOK, &pnl) == -1) { 576 pnl.direction = PF_OUT; 577 cnl->in = 0; 578 if (ioctl(env->sc_pf->dev, DIOCNATLOOK, &pnl) == -1) { 579 log_debug("natlook: error: %s", strerror(errno)); 580 return (-1); 581 } 582 } 583 584 inet_ntop(pnl.af, &pnl.rsaddr, ibuf, sizeof(ibuf)); 585 inet_ntop(pnl.af, &pnl.rdaddr, obuf, sizeof(obuf)); 586 log_debug("natlook: %s %s:%d -> %s:%d", 587 pnl.direction == PF_IN ? "in" : "out", 588 ibuf, ntohs(pnl.rsport), obuf, ntohs(pnl.rdport)); 589 590 switch (pnl.af) { 591 case AF_INET: 592 in = (struct sockaddr_in *)&cnl->rsrc; 593 out = (struct sockaddr_in *)&cnl->rdst; 594 bcopy(&pnl.rsaddr.v4, &in->sin_addr, sizeof(in->sin_addr)); 595 in->sin_port = pnl.rsport; 596 bcopy(&pnl.rdaddr.v4, &out->sin_addr, sizeof(out->sin_addr)); 597 out->sin_port = pnl.rdport; 598 break; 599 case AF_INET6: 600 in6 = (struct sockaddr_in6 *)&cnl->rsrc; 601 out6 = (struct sockaddr_in6 *)&cnl->rdst; 602 bcopy(&pnl.rsaddr.v6, &in6->sin6_addr, sizeof(in6->sin6_addr)); 603 bcopy(&pnl.rdaddr.v6, &out6->sin6_addr, 604 sizeof(out6->sin6_addr)); 605 break; 606 } 607 cnl->rsrc.ss_family = pnl.af; 608 cnl->rdst.ss_family = pnl.af; 609 cnl->rsport = pnl.rsport; 610 cnl->rdport = pnl.rdport; 611 612 return (0); 613 } 614 615 u_int64_t 616 check_table(struct relayd *env, struct rdr *rdr, struct table *table) 617 { 618 struct pfioc_table io; 619 struct pfr_tstats tstats; 620 621 if (table == NULL) 622 return (0); 623 624 bzero(&io, sizeof(io)); 625 io.pfrio_esize = sizeof(struct pfr_tstats); 626 io.pfrio_size = 1; 627 io.pfrio_buffer = &tstats; 628 if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/", 629 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 630 goto toolong; 631 if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name, 632 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 633 goto toolong; 634 if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name, 635 sizeof(io.pfrio_table.pfrt_name)) >= 636 sizeof(io.pfrio_table.pfrt_name)) 637 goto toolong; 638 639 if (ioctl(env->sc_pf->dev, DIOCRGETTSTATS, &io) == -1) 640 fatal("check_table: cannot get table stats"); 641 642 return (tstats.pfrts_match); 643 644 toolong: 645 fatal("check_table: name too long"); 646 return (0); 647 } 648