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