1 /* $OpenBSD: pfe_filter.c,v 1.49 2012/07/07 16:24:32 henning 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 rio.rule.onrdomain = getrtable(); 443 rio.rule.set_prio[0] = rio.rule.set_prio[1] = PF_PRIO_NOTSET; 444 445 if (rio.rule.proto == IPPROTO_TCP) 446 rio.rule.timeout[PFTM_TCP_ESTABLISHED] = 447 rdr->conf.timeout.tv_sec; 448 449 if (strlen(rdr->conf.tag)) 450 (void)strlcpy(rio.rule.tagname, rdr->conf.tag, 451 sizeof(rio.rule.tagname)); 452 if (strlen(address->ifname)) 453 (void)strlcpy(rio.rule.ifname, address->ifname, 454 sizeof(rio.rule.ifname)); 455 456 if (address->ss.ss_family == AF_INET) { 457 sain = (struct sockaddr_in *)&address->ss; 458 459 rio.rule.dst.addr.v.a.addr.addr32[0] = 460 sain->sin_addr.s_addr; 461 rio.rule.dst.addr.v.a.mask.addr32[0] = 0xffffffff; 462 } else { 463 sain6 = (struct sockaddr_in6 *)&address->ss; 464 465 memcpy(&rio.rule.dst.addr.v.a.addr.v6, 466 &sain6->sin6_addr.s6_addr, 467 sizeof(sain6->sin6_addr.s6_addr)); 468 memset(&rio.rule.dst.addr.v.a.mask.addr8, 0xff, 16); 469 } 470 471 rio.rule.nat.addr.type = PF_ADDR_NONE; 472 rio.rule.rdr.addr.type = PF_ADDR_TABLE; 473 if (strlen(t->conf.ifname)) 474 (void)strlcpy(rio.rule.rdr.ifname, t->conf.ifname, 475 sizeof(rio.rule.rdr.ifname)); 476 if (strlcpy(rio.rule.rdr.addr.v.tblname, rdr->conf.name, 477 sizeof(rio.rule.rdr.addr.v.tblname)) >= 478 sizeof(rio.rule.rdr.addr.v.tblname)) 479 fatal("sync_ruleset: table name too long"); 480 481 if (address->port.op == PF_OP_EQ || 482 rdr->table->conf.flags & F_PORT) { 483 rio.rule.rdr.proxy_port[0] = 484 ntohs(rdr->table->conf.port); 485 rio.rule.rdr.port_op = PF_OP_EQ; 486 } 487 rio.rule.rdr.opts = PF_POOL_ROUNDROBIN; 488 if (rdr->conf.flags & F_STICKY) 489 rio.rule.rdr.opts |= PF_POOL_STICKYADDR; 490 491 if (rio.rule.rt == PF_ROUTETO) { 492 memcpy(&rio.rule.route, &rio.rule.rdr, 493 sizeof(rio.rule.route)); 494 rio.rule.rdr.addr.type = PF_ADDR_NONE; 495 } 496 497 if (ioctl(env->sc_pf->dev, DIOCADDRULE, &rio) == -1) 498 fatal("cannot add rule"); 499 log_debug("%s: rule added to anchor \"%s\"", __func__, anchor); 500 } 501 if (transaction_commit(env) == -1) 502 log_warn("%s: add rules transaction failed", __func__); 503 return; 504 505 toolong: 506 fatal("sync_ruleset: name too long"); 507 } 508 509 void 510 flush_rulesets(struct relayd *env) 511 { 512 struct rdr *rdr; 513 char anchor[PF_ANCHOR_NAME_SIZE]; 514 515 if (!(env->sc_flags & F_NEEDPF)) 516 return; 517 518 kill_tables(env); 519 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 520 if (strlcpy(anchor, RELAYD_ANCHOR "/", sizeof(anchor)) >= 521 PF_ANCHOR_NAME_SIZE) 522 goto toolong; 523 if (strlcat(anchor, rdr->conf.name, sizeof(anchor)) >= 524 PF_ANCHOR_NAME_SIZE) 525 goto toolong; 526 if (transaction_init(env, anchor) == -1 || 527 transaction_commit(env) == -1) 528 log_warn("%s: transaction for %s/ failed", __func__, 529 RELAYD_ANCHOR); 530 } 531 if (strlcpy(anchor, RELAYD_ANCHOR, sizeof(anchor)) >= 532 PF_ANCHOR_NAME_SIZE) 533 goto toolong; 534 if (transaction_init(env, anchor) == -1 || 535 transaction_commit(env) == -1) 536 log_warn("%s: transaction for %s failed", __func__, 537 RELAYD_ANCHOR); 538 log_debug("%s: flushed rules", __func__); 539 return; 540 541 toolong: 542 fatal("flush_rulesets: name too long"); 543 } 544 545 int 546 natlook(struct relayd *env, struct ctl_natlook *cnl) 547 { 548 struct pfioc_natlook pnl; 549 struct sockaddr_in *in, *out; 550 struct sockaddr_in6 *in6, *out6; 551 char ibuf[BUFSIZ], obuf[BUFSIZ]; 552 553 if (!(env->sc_flags & F_NEEDPF)) 554 return (0); 555 556 bzero(&pnl, sizeof(pnl)); 557 558 if ((pnl.af = cnl->src.ss_family) != cnl->dst.ss_family) 559 fatalx("natlook: illegal address families"); 560 switch (pnl.af) { 561 case AF_INET: 562 in = (struct sockaddr_in *)&cnl->src; 563 out = (struct sockaddr_in *)&cnl->dst; 564 bcopy(&in->sin_addr, &pnl.saddr.v4, sizeof(pnl.saddr.v4)); 565 pnl.sport = in->sin_port; 566 bcopy(&out->sin_addr, &pnl.daddr.v4, sizeof(pnl.daddr.v4)); 567 pnl.dport = out->sin_port; 568 break; 569 case AF_INET6: 570 in6 = (struct sockaddr_in6 *)&cnl->src; 571 out6 = (struct sockaddr_in6 *)&cnl->dst; 572 bcopy(&in6->sin6_addr, &pnl.saddr.v6, sizeof(pnl.saddr.v6)); 573 pnl.sport = in6->sin6_port; 574 bcopy(&out6->sin6_addr, &pnl.daddr.v6, sizeof(pnl.daddr.v6)); 575 pnl.dport = out6->sin6_port; 576 } 577 pnl.proto = cnl->proto; 578 pnl.direction = PF_IN; 579 cnl->in = 1; 580 581 if (ioctl(env->sc_pf->dev, DIOCNATLOOK, &pnl) == -1) { 582 pnl.direction = PF_OUT; 583 cnl->in = 0; 584 if (ioctl(env->sc_pf->dev, DIOCNATLOOK, &pnl) == -1) { 585 log_debug("%s: ioctl: %s", __func__, strerror(errno)); 586 return (-1); 587 } 588 } 589 590 inet_ntop(pnl.af, &pnl.rsaddr, ibuf, sizeof(ibuf)); 591 inet_ntop(pnl.af, &pnl.rdaddr, obuf, sizeof(obuf)); 592 log_debug("%s: %s %s:%d -> %s:%d", __func__, 593 pnl.direction == PF_IN ? "in" : "out", 594 ibuf, ntohs(pnl.rsport), obuf, ntohs(pnl.rdport)); 595 596 switch (pnl.af) { 597 case AF_INET: 598 in = (struct sockaddr_in *)&cnl->rsrc; 599 out = (struct sockaddr_in *)&cnl->rdst; 600 bcopy(&pnl.rsaddr.v4, &in->sin_addr, sizeof(in->sin_addr)); 601 in->sin_port = pnl.rsport; 602 bcopy(&pnl.rdaddr.v4, &out->sin_addr, sizeof(out->sin_addr)); 603 out->sin_port = pnl.rdport; 604 break; 605 case AF_INET6: 606 in6 = (struct sockaddr_in6 *)&cnl->rsrc; 607 out6 = (struct sockaddr_in6 *)&cnl->rdst; 608 bcopy(&pnl.rsaddr.v6, &in6->sin6_addr, sizeof(in6->sin6_addr)); 609 bcopy(&pnl.rdaddr.v6, &out6->sin6_addr, 610 sizeof(out6->sin6_addr)); 611 break; 612 } 613 cnl->rsrc.ss_family = pnl.af; 614 cnl->rdst.ss_family = pnl.af; 615 cnl->rsport = pnl.rsport; 616 cnl->rdport = pnl.rdport; 617 618 return (0); 619 } 620 621 u_int64_t 622 check_table(struct relayd *env, struct rdr *rdr, struct table *table) 623 { 624 struct pfioc_table io; 625 struct pfr_tstats tstats; 626 627 if (table == NULL) 628 return (0); 629 630 bzero(&io, sizeof(io)); 631 io.pfrio_esize = sizeof(struct pfr_tstats); 632 io.pfrio_size = 1; 633 io.pfrio_buffer = &tstats; 634 if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/", 635 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 636 goto toolong; 637 if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name, 638 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 639 goto toolong; 640 if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name, 641 sizeof(io.pfrio_table.pfrt_name)) >= 642 sizeof(io.pfrio_table.pfrt_name)) 643 goto toolong; 644 645 if (ioctl(env->sc_pf->dev, DIOCRGETTSTATS, &io) == -1) 646 fatal("check_table: cannot get table stats"); 647 648 return (tstats.pfrts_match); 649 650 toolong: 651 fatal("check_table: name too long"); 652 return (0); 653 } 654