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