xref: /openbsd/usr.sbin/relayd/pfe_filter.c (revision 7c726e76)
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