1 /* $OpenBSD: pfe_filter.c,v 1.66 2024/06/17 08:02:57 sashan 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/time.h> 23 #include <sys/ioctl.h> 24 25 #include <net/if.h> 26 #include <netinet/in.h> 27 #include <netinet/tcp.h> 28 #include <arpa/inet.h> 29 #include <net/pfvar.h> 30 31 #include <limits.h> 32 #include <string.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <errno.h> 37 38 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 39 40 #include "relayd.h" 41 42 int transaction_init(struct relayd *, const char *); 43 int transaction_commit(struct relayd *); 44 void kill_tables(struct relayd *); 45 int kill_srcnodes(struct relayd *, struct table *); 46 47 void 48 init_tables(struct relayd *env) 49 { 50 int i; 51 struct rdr *rdr; 52 struct pfr_table *tables; 53 struct pfioc_table io; 54 55 if (!(env->sc_conf.flags & F_NEEDPF)) 56 return; 57 58 if ((tables = calloc(env->sc_rdrcount, sizeof(*tables))) == NULL) 59 fatal("calloc"); 60 i = 0; 61 62 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 63 if (strlcpy(tables[i].pfrt_anchor, RELAYD_ANCHOR "/", 64 sizeof(tables[i].pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 65 goto toolong; 66 if (strlcat(tables[i].pfrt_anchor, rdr->conf.name, 67 sizeof(tables[i].pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 68 goto toolong; 69 if (strlcpy(tables[i].pfrt_name, rdr->conf.name, 70 sizeof(tables[i].pfrt_name)) >= 71 sizeof(tables[i].pfrt_name)) 72 goto toolong; 73 tables[i].pfrt_flags |= PFR_TFLAG_PERSIST; 74 i++; 75 } 76 if (i != env->sc_rdrcount) 77 fatalx("%s: table count modified", __func__); 78 79 memset(&io, 0, sizeof(io)); 80 io.pfrio_size = env->sc_rdrcount; 81 io.pfrio_esize = sizeof(*tables); 82 io.pfrio_buffer = tables; 83 84 if (ioctl(env->sc_pf->dev, DIOCRADDTABLES, &io) == -1) 85 fatal("%s: cannot create tables", __func__); 86 log_debug("%s: created %d tables", __func__, io.pfrio_nadd); 87 88 free(tables); 89 90 if (io.pfrio_nadd == env->sc_rdrcount) 91 return; 92 93 /* 94 * clear all tables, since some already existed 95 */ 96 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) 97 flush_table(env, rdr); 98 99 return; 100 101 toolong: 102 fatal("%s: name too long", __func__); 103 } 104 105 void 106 kill_tables(struct relayd *env) 107 { 108 struct pfioc_table io; 109 struct rdr *rdr; 110 int cnt = 0; 111 112 if (!(env->sc_conf.flags & F_NEEDPF)) 113 return; 114 115 TAILQ_FOREACH(rdr, env->sc_rdrs, entry) { 116 memset(&io, 0, sizeof(io)); 117 if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/", 118 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 119 goto toolong; 120 if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name, 121 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 122 goto toolong; 123 if (ioctl(env->sc_pf->dev, DIOCRCLRTABLES, &io) == -1) 124 fatal("%s: ioctl failed", __func__); 125 cnt += io.pfrio_ndel; 126 } 127 log_debug("%s: deleted %d tables", __func__, cnt); 128 return; 129 130 toolong: 131 fatal("%s: name too long", __func__); 132 } 133 134 void 135 sync_table(struct relayd *env, struct rdr *rdr, struct table *table) 136 { 137 int i, cnt = 0; 138 struct pfioc_table io; 139 struct pfr_addr *addlist; 140 struct sockaddr_in *sain; 141 struct sockaddr_in6 *sain6; 142 struct host *host; 143 144 if (!(env->sc_conf.flags & F_NEEDPF)) 145 return; 146 147 if (table == NULL) 148 return; 149 150 if (table->up == 0) { 151 flush_table(env, rdr); 152 return; 153 } 154 155 if ((addlist = calloc(table->up, sizeof(*addlist))) == NULL) 156 fatal("calloc"); 157 158 memset(&io, 0, sizeof(io)); 159 io.pfrio_esize = sizeof(struct pfr_addr); 160 io.pfrio_size = table->up; 161 io.pfrio_size2 = 0; 162 io.pfrio_buffer = addlist; 163 if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/", 164 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 165 goto toolong; 166 if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name, 167 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 168 goto toolong; 169 if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name, 170 sizeof(io.pfrio_table.pfrt_name)) >= 171 sizeof(io.pfrio_table.pfrt_name)) 172 goto toolong; 173 174 i = 0; 175 TAILQ_FOREACH(host, &table->hosts, entry) { 176 if (host->up != HOST_UP) 177 continue; 178 memset(&(addlist[i]), 0, sizeof(addlist[i])); 179 switch (host->conf.ss.ss_family) { 180 case AF_INET: 181 sain = (struct sockaddr_in *)&host->conf.ss; 182 addlist[i].pfra_af = AF_INET; 183 memcpy(&(addlist[i].pfra_ip4addr), &sain->sin_addr, 184 sizeof(sain->sin_addr)); 185 addlist[i].pfra_net = 32; 186 break; 187 case AF_INET6: 188 sain6 = (struct sockaddr_in6 *)&host->conf.ss; 189 addlist[i].pfra_af = AF_INET6; 190 memcpy(&(addlist[i].pfra_ip6addr), &sain6->sin6_addr, 191 sizeof(sain6->sin6_addr)); 192 addlist[i].pfra_net = 128; 193 break; 194 default: 195 fatalx("%s: unknown address family", __func__); 196 break; 197 } 198 i++; 199 } 200 if (i != table->up) 201 fatalx("%s: desynchronized", __func__); 202 203 if (ioctl(env->sc_pf->dev, DIOCRSETADDRS, &io) == -1) 204 fatal("%s: cannot set address list", __func__); 205 if (rdr->conf.flags & F_STICKY) 206 cnt = kill_srcnodes(env, table); 207 free(addlist); 208 209 if (env->sc_conf.opts & RELAYD_OPT_LOGUPDATE) 210 log_info("table %s: %d added, %d deleted, " 211 "%d changed, %d killed", io.pfrio_table.pfrt_name, 212 io.pfrio_nadd, io.pfrio_ndel, io.pfrio_nchange, cnt); 213 return; 214 215 toolong: 216 fatal("%s: name too long", __func__); 217 } 218 219 int 220 kill_srcnodes(struct relayd *env, struct table *table) 221 { 222 struct host *host; 223 struct pfioc_src_node_kill psnk; 224 int cnt = 0; 225 struct sockaddr_in *sain; 226 struct sockaddr_in6 *sain6; 227 228 bzero(&psnk, sizeof(psnk)); 229 230 /* Only match the destination address, source mask will be zero */ 231 memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, 232 sizeof(psnk.psnk_dst.addr.v.a.mask)); 233 234 TAILQ_FOREACH(host, &table->hosts, entry) { 235 if (host->up != HOST_DOWN) 236 continue; 237 238 switch (host->conf.ss.ss_family) { 239 case AF_INET: 240 sain = (struct sockaddr_in *)&host->conf.ss; 241 bcopy(&sain->sin_addr, 242 &psnk.psnk_dst.addr.v.a.addr.v4, 243 sizeof(psnk.psnk_dst.addr.v.a.addr.v4)); 244 break; 245 case AF_INET6: 246 sain6 = (struct sockaddr_in6 *)&host->conf.ss; 247 bcopy(&sain6->sin6_addr, 248 &psnk.psnk_dst.addr.v.a.addr.v6, 249 sizeof(psnk.psnk_dst.addr.v.a.addr.v6)); 250 break; 251 default: 252 fatalx("%s: unknown address family", __func__); 253 break; 254 } 255 256 psnk.psnk_af = host->conf.ss.ss_family; 257 psnk.psnk_killed = 0; 258 259 if (ioctl(env->sc_pf->dev, 260 DIOCKILLSRCNODES, &psnk) == -1) 261 fatal("%s: cannot kill src nodes", __func__); 262 cnt += psnk.psnk_killed; 263 } 264 265 return (cnt); 266 } 267 268 void 269 flush_table(struct relayd *env, struct rdr *rdr) 270 { 271 struct pfioc_table io; 272 273 if (!(env->sc_conf.flags & F_NEEDPF)) 274 return; 275 276 memset(&io, 0, sizeof(io)); 277 if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/", 278 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 279 goto toolong; 280 if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name, 281 sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE) 282 goto toolong; 283 if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name, 284 sizeof(io.pfrio_table.pfrt_name)) >= 285 sizeof(io.pfrio_table.pfrt_name)) 286 goto toolong; 287 if (ioctl(env->sc_pf->dev, DIOCRCLRADDRS, &io) == -1) 288 fatal("%s: cannot flush table addresses", __func__); 289 290 io.pfrio_esize = sizeof(io.pfrio_table); 291 io.pfrio_size = 1; 292 io.pfrio_buffer = &io.pfrio_table; 293 if (ioctl(env->sc_pf->dev, DIOCRCLRTSTATS, &io) == -1) 294 fatal("%s: cannot flush table stats", __func__); 295 296 log_debug("%s: flushed table %s", __func__, rdr->conf.name); 297 return; 298 299 toolong: 300 fatal("%s: name too long", __func__); 301 } 302 303 int 304 transaction_init(struct relayd *env, const char *anchor) 305 { 306 env->sc_pf->pft.size = 1; 307 env->sc_pf->pft.esize = sizeof(env->sc_pf->pfte); 308 env->sc_pf->pft.array = &env->sc_pf->pfte; 309 310 bzero(&env->sc_pf->pfte, sizeof(env->sc_pf->pfte)); 311 (void)strlcpy(env->sc_pf->pfte.anchor, 312 anchor, PF_ANCHOR_NAME_SIZE); 313 env->sc_pf->pfte.type = PF_TRANS_RULESET; 314 315 if (ioctl(env->sc_pf->dev, DIOCXBEGIN, 316 &env->sc_pf->pft) == -1) 317 return (-1); 318 319 return (0); 320 } 321 322 int 323 transaction_commit(struct relayd *env) 324 { 325 if (ioctl(env->sc_pf->dev, DIOCXCOMMIT, 326 &env->sc_pf->pft) == -1) 327 return (-1); 328 329 return (0); 330 } 331 332 void 333 sync_ruleset(struct relayd *env, struct rdr *rdr, int enable) 334 { 335 struct pfioc_rule rio; 336 struct sockaddr_in *sain; 337 struct sockaddr_in6 *sain6; 338 struct address *address; 339 char anchor[PF_ANCHOR_NAME_SIZE]; 340 struct table *t = rdr->table; 341 342 if ((env->sc_conf.flags & F_NEEDPF) == 0) 343 return; 344 345 bzero(anchor, sizeof(anchor)); 346 if (strlcpy(anchor, RELAYD_ANCHOR "/", sizeof(anchor)) >= 347 PF_ANCHOR_NAME_SIZE) 348 goto toolong; 349 if (strlcat(anchor, rdr->conf.name, sizeof(anchor)) >= 350 PF_ANCHOR_NAME_SIZE) 351 goto toolong; 352 if (transaction_init(env, anchor) == -1) { 353 log_warn("%s: transaction init failed", __func__); 354 return; 355 } 356 357 if (!enable) { 358 if (transaction_commit(env) == -1) 359 log_warn("%s: remove rules transaction failed", 360 __func__); 361 else 362 log_debug("%s: rules removed", __func__); 363 return; 364 } 365 366 TAILQ_FOREACH(address, &rdr->virts, entry) { 367 memset(&rio, 0, sizeof(rio)); 368 (void)strlcpy(rio.anchor, anchor, sizeof(rio.anchor)); 369 370 if (rdr->conf.flags & F_MATCH) { 371 rio.rule.action = PF_MATCH; 372 rio.rule.quick = 0; 373 } else { 374 rio.rule.action = PF_PASS; 375 rio.rule.quick = 1; /* force first match */ 376 } 377 rio.rule.direction = PF_IN; 378 rio.rule.keep_state = PF_STATE_NORMAL; 379 380 if (rdr->conf.flags & F_PFLOG) 381 rio.rule.log = 1; 382 else 383 rio.rule.log = 0; /* allow change via reload */ 384 385 switch (t->conf.fwdmode) { 386 case FWD_NORMAL: 387 /* traditional redirection */ 388 if (address->ipproto == IPPROTO_TCP) { 389 rio.rule.flags = TH_SYN; 390 rio.rule.flagset = (TH_SYN|TH_ACK); 391 } 392 break; 393 case FWD_ROUTE: 394 /* re-route with pf for DSR (direct server return) */ 395 rio.rule.rt = PF_ROUTETO; 396 397 /* Use sloppy state handling for half connections */ 398 rio.rule.rule_flag = PFRULE_STATESLOPPY; 399 break; 400 default: 401 fatalx("%s: invalid forward mode", __func__); 402 /* NOTREACHED */ 403 } 404 405 rio.ticket = env->sc_pf->pfte.ticket; 406 407 rio.rule.af = address->ss.ss_family; 408 rio.rule.proto = address->ipproto; 409 rio.rule.src.addr.type = PF_ADDR_ADDRMASK; 410 rio.rule.dst.addr.type = PF_ADDR_ADDRMASK; 411 rio.rule.dst.port_op = address->port.op; 412 rio.rule.dst.port[0] = address->port.val[0]; 413 rio.rule.dst.port[1] = address->port.val[1]; 414 rio.rule.rtableid = -1; /* stay in the main routing table */ 415 rio.rule.onrdomain = env->sc_rtable; 416 DPRINTF("%s rtable %d",__func__,env->sc_rtable); 417 418 if (rio.rule.proto == IPPROTO_TCP) 419 rio.rule.timeout[PFTM_TCP_ESTABLISHED] = 420 (u_int32_t)MINIMUM(rdr->conf.timeout.tv_sec, 421 INT_MAX); 422 423 if (strlen(rdr->conf.tag)) 424 (void)strlcpy(rio.rule.tagname, rdr->conf.tag, 425 sizeof(rio.rule.tagname)); 426 if (strlen(address->ifname)) 427 (void)strlcpy(rio.rule.ifname, address->ifname, 428 sizeof(rio.rule.ifname)); 429 430 if (address->ss.ss_family == AF_INET) { 431 sain = (struct sockaddr_in *)&address->ss; 432 433 rio.rule.dst.addr.v.a.addr.addr32[0] = 434 sain->sin_addr.s_addr; 435 rio.rule.dst.addr.v.a.mask.addr32[0] = 0xffffffff; 436 } else { 437 sain6 = (struct sockaddr_in6 *)&address->ss; 438 439 memcpy(&rio.rule.dst.addr.v.a.addr.v6, 440 &sain6->sin6_addr.s6_addr, 441 sizeof(sain6->sin6_addr.s6_addr)); 442 memset(&rio.rule.dst.addr.v.a.mask.addr8, 0xff, 16); 443 } 444 445 rio.rule.nat.addr.type = PF_ADDR_NONE; 446 rio.rule.rdr.addr.type = PF_ADDR_TABLE; 447 if (strlen(t->conf.ifname)) 448 (void)strlcpy(rio.rule.rdr.ifname, t->conf.ifname, 449 sizeof(rio.rule.rdr.ifname)); 450 if (strlcpy(rio.rule.rdr.addr.v.tblname, rdr->conf.name, 451 sizeof(rio.rule.rdr.addr.v.tblname)) >= 452 sizeof(rio.rule.rdr.addr.v.tblname)) 453 fatal("%s: table name too long", __func__); 454 455 if (address->port.op == PF_OP_EQ || 456 rdr->table->conf.flags & F_PORT) { 457 rio.rule.rdr.proxy_port[0] = 458 ntohs(rdr->table->conf.port); 459 rio.rule.rdr.port_op = PF_OP_EQ; 460 } 461 462 switch (rdr->conf.mode) { 463 case RELAY_DSTMODE_RANDOM: 464 rio.rule.rdr.opts = PF_POOL_RANDOM; 465 break; 466 case RELAY_DSTMODE_ROUNDROBIN: 467 rio.rule.rdr.opts = PF_POOL_ROUNDROBIN; 468 break; 469 case RELAY_DSTMODE_SRCHASH: 470 rio.rule.rdr.opts = PF_POOL_SRCHASH; 471 break; 472 case RELAY_DSTMODE_LEASTSTATES: 473 rio.rule.rdr.opts = PF_POOL_LEASTSTATES; 474 break; 475 default: 476 fatalx("%s: unsupported mode", __func__); 477 /* NOTREACHED */ 478 } 479 if (rdr->conf.flags & F_STICKY) 480 rio.rule.rdr.opts |= PF_POOL_STICKYADDR; 481 if (rdr->conf.flags & F_HASHKEY) 482 memcpy(rio.rule.rdr.key.key32, rdr->conf.key.data, 483 sizeof(rio.rule.rdr.key.key32)); 484 485 if (rio.rule.rt == PF_ROUTETO) { 486 memcpy(&rio.rule.route, &rio.rule.rdr, 487 sizeof(rio.rule.route)); 488 rio.rule.rdr.addr.type = PF_ADDR_NONE; 489 } 490 491 if (ioctl(env->sc_pf->dev, DIOCADDRULE, &rio) == -1) 492 fatal("cannot add rule"); 493 log_debug("%s: rule added to anchor \"%s\"", __func__, anchor); 494 } 495 if (transaction_commit(env) == -1) 496 log_warn("%s: add rules transaction failed", __func__); 497 return; 498 499 toolong: 500 fatal("%s: name too long", __func__); 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_conf.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("%s: transaction for %s/ failed", __func__, 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("%s: transaction for %s failed", __func__, 531 RELAYD_ANCHOR); 532 log_debug("%s: flushed rules", __func__); 533 return; 534 535 toolong: 536 fatal("%s: name too long", __func__); 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_conf.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("%s: illegal address families", __func__); 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("%s: ioctl: %s", __func__, 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("%s: %s %s:%d -> %s:%d", __func__, 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("%s: cannot get table stats for %s@%s", __func__, 641 io.pfrio_table.pfrt_name, io.pfrio_table.pfrt_anchor); 642 643 return (tstats.pfrts_match); 644 645 toolong: 646 fatal("%s: name too long", __func__); 647 return (0); 648 } 649