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
init_tables(struct relayd * env)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
kill_tables(struct relayd * env)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
sync_table(struct relayd * env,struct rdr * rdr,struct table * table)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
kill_srcnodes(struct relayd * env,struct table * table)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
flush_table(struct relayd * env,struct rdr * rdr)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
transaction_init(struct relayd * env,const char * anchor)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
transaction_commit(struct relayd * env)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
sync_ruleset(struct relayd * env,struct rdr * rdr,int enable)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
flush_rulesets(struct relayd * env)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
natlook(struct relayd * env,struct ctl_natlook * cnl)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
check_table(struct relayd * env,struct rdr * rdr,struct table * table)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